Include JavaScript Dynamically: What's Wrong?

0 views
Skip to first unread message

vunet

unread,
Feb 4, 2009, 9:16:58 AM2/4/09
to
I create a RIA app where I plan on including some JavaScript libraries
dynamically, i.e. using document.write("<script type='text/javascript'
src='xxx'></script>"). I heard from some experts this is not a good
practice. One thing I did not hear is why. Can anyone explain? Also,
Scriptaculos works the same way where it includes the files of the
library with document.write. It works in possibly all browsers. What
is the disadvantage though?
Thanks for good advice.

Peter May

unread,
Feb 4, 2009, 9:31:18 AM2/4/09
to
vunet pisze:

Good way to do this is using DOM scripting. For example:

var headElement = document.getElementsByTagName('head')[0];
var linkElement = document.createElement('link');
linkElement.setAttribute('type', 'text/javascript');
linkElement.setAttribute('href', 'URL to script');
headElement.appendChild(linkElement);

If You send Your content from server with header application/xhtml+xml
then document.write() will not work in XHTML contexts. You have to use
DOM methods.

--
Peter

vunet

unread,
Feb 4, 2009, 10:08:00 AM2/4/09
to

Thank you. Though I know about DOM insertion, there is a Safari (I
believe v.2) issue where the above solution will not work (But I did
not test myself). Also, what do you mean "from server with header
application/xhtml+xml"? Is it set on the server side in the header?

Will this be better (just found for Scriptaculos fix):

try {
script_tag = document.createElement('script');
script_tag.setAttribute('type','text/javascript');
script_tag.setAttribute('src',libraryName);
head = document.getElementsByTagName("head")[0];
head.appendChild(script_tag);
} catch(e) {
// inserting via DOM fails in Safari 2.0, so brute force approach
document.write('<script type="text/javascript" src="'+libraryName
+'"></script>');
}

Peter May

unread,
Feb 4, 2009, 10:25:14 AM2/4/09
to
vunet pisze:
[...]

> Thank you. Though I know about DOM insertion, there is a Safari (I
> believe v.2) issue where the above solution will not work (But I did
> not test myself). Also, what do you mean "from server with header
> application/xhtml+xml"? Is it set on the server side in the header?

http://www.w3.org/TR/xhtml-media-types/#application-xhtml-xml

> Will this be better (just found for Scriptaculos fix):

Not tested the solution I have given on Safari. It is possible that this
may not work. If so, let someone could confirm for the group.

> try {
> script_tag = document.createElement('script');
> script_tag.setAttribute('type','text/javascript');
> script_tag.setAttribute('src',libraryName);
> head = document.getElementsByTagName("head")[0];
> head.appendChild(script_tag);
> } catch(e) {
> // inserting via DOM fails in Safari 2.0, so brute force approach
> document.write('<script type="text/javascript" src="'+libraryName
> +'"></script>');
> }

--
Peter

Thomas 'PointedEars' Lahn

unread,
Feb 4, 2009, 1:58:55 PM2/4/09
to
Peter May wrote:
> vunet pisze:
>> I create a RIA app where I plan on including some JavaScript libraries
>> dynamically, i.e. using document.write("<script type='text/javascript'
>> src='xxx'></script>"). I heard from some experts this is not a good
>> practice.

True, if your markup is HTML and this call is within a `script' element, you
should escape ETAGO delimiters:

document.write('<script type="text/javascript" src="xxx"><\/script>');

>> One thing I did not hear is why. Can anyone explain? Also,
>> Scriptaculos works the same way where it includes the files of the
>> library with document.write.

Script.aculo.us is based on Prototype.js, which is junk.

>> It works in possibly all browsers.

Probably not. For a start, it doesn't work reliably in Netscape 4.x due to
the NRLB.

>> What is the disadvantage though?

See above.

>> Thanks for good advice.
>
> Good way to do this is using DOM scripting. For example:
>
> var headElement = document.getElementsByTagName('head')[0];

Always feature-test properties before you access them; always feature-test
methods before you call them:

if (isMethod(document, "getElementsByTagName"))
{
var headElements = document.getElementsByTagName('head');
if (headElement)
{
var headELement = headElements[0];
// ...
}
}

One possible implementation of isMethod() can be found in
<http://PointedEars.de/scripts/types.js>. The newsgroup's archives
and other regular's Web sites provide plenty of others, I suppose.

> var linkElement = document.createElement('link');

See above.

> linkElement.setAttribute('type', 'text/javascript');

See above.

> linkElement.setAttribute('href', 'URL to script');

See above.

Never use setAttribute() if an shorthand property would do.

linkElement.type = ...;
linkElement.href = ...;

> headElement.appendChild(linkElement);

See above.

As for the whole approach, see also loadScript() in
<http://PointedEars.de/scripts/dhtml.js>.

> If You send Your content from server with header application/xhtml+xml

> then document.write() will not work in XHTML contexts.js

At least not reliably.

> You have to use DOM methods.

document.write() *is* a DOM method, though, both in the general sense and
regarding the W3C DOM.


PointedEars

Jorge

unread,
Feb 4, 2009, 2:25:59 PM2/4/09
to

javascript:(function(){document.body.appendChild(document.createElement
('script')).innerHTML="alert('hi !');"})()

:-)

--
Jorge.

Martin Rinehart

unread,
Feb 4, 2009, 2:49:19 PM2/4/09
to
On Feb 4, 1:58 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Probably not.  For a start, it doesn't work reliably in Netscape 4.x due to
> the NRLB.

Were you being serious or sarcastic?

Jorge

unread,
Feb 5, 2009, 11:06:35 AM2/5/09
to

Or:

javascript:void (document.body.previousSibling.appendChild
(document.createElement('script')).src= "http://jorgechamorro.com/
alertHi.js");

--
Jorge.

Peter May

unread,
Feb 6, 2009, 8:27:37 AM2/6/09
to
Thomas 'PointedEars' Lahn pisze:

> Peter May wrote:
>> Good way to do this is using DOM scripting. For example:
>>
>> var headElement = document.getElementsByTagName('head')[0];
>
> Always feature-test properties before you access them; always feature-test
> methods before you call them:
>
> if (isMethod(document, "getElementsByTagName"))
> {
> var headElements = document.getElementsByTagName('head');
> if (headElement)
> {
> var headELement = headElements[0];
> // ...
> }
> }
>
> One possible implementation of isMethod() can be found in
> <http://PointedEars.de/scripts/types.js>. The newsgroup's archives
> and other regular's Web sites provide plenty of others, I suppose.

It was just an example that you can always upgrade to verify whether the
methods work.

>> var linkElement = document.createElement('link');
>
> See above.
>
>> linkElement.setAttribute('type', 'text/javascript');
>
> See above.
>
>> linkElement.setAttribute('href', 'URL to script');
>
> See above.
>
> Never use setAttribute() if an shorthand property would do.
>
> linkElement.type = ...;
> linkElement.href = ...;

Why?

>> headElement.appendChild(linkElement);
>
> See above.
>
> As for the whole approach, see also loadScript() in
> <http://PointedEars.de/scripts/dhtml.js>.
>
>> If You send Your content from server with header application/xhtml+xml
>> then document.write() will not work in XHTML contexts.js
>
> At least not reliably.
>
>> You have to use DOM methods.
>
> document.write() *is* a DOM method, though, both in the general sense and
> regarding the W3C DOM.

http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75233634

"Note that the function will produce a document which is not necessarily
driven by a DTD and therefore might be produce an invalid result in the
context of the document."

--
Peter

Gregor Kofler

unread,
Feb 6, 2009, 9:07:17 AM2/6/09
to
Peter May meinte:

>> Never use setAttribute() if an shorthand property would do.
>>
>> linkElement.type = ...;
>> linkElement.href = ...;
>
> Why?

Most of the time it's just superfluous (and I assume slower). Anyway,
google for "internet explorer setattribute problem".

HTH, Gregor

Thomas 'PointedEars' Lahn

unread,
Feb 6, 2009, 9:17:06 AM2/6/09
to
Peter May wrote:
Thomas 'PointedEars' Lahn pisze:

>>> You have to use DOM methods.
>> document.write() *is* a DOM method, though, both in the general sense and
>> regarding the W3C DOM.
> http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75233634
>
> "Note that the function will produce a document which is not necessarily
> driven by a DTD and therefore might be produce an invalid result in the
> context of the document."

The method itself is nevertheless a standards-compliant one. It is part of
a normative section of a public Specification, a W3C Recommendation. On
closer look you will observe that it is one of several features originating
from the proprietary "DOM Level 0" that have been standardized in W3C DOM
HTML, Levels 1 (now obsolete) and 2.

In any case, the term "DOM" (Document Object Model) is not restricted to
that of the W3C DOM.

Trim your quotes, please. <http://jibbering.com/faq/#posting>


PointedEars

Peter May

unread,
Feb 6, 2009, 11:07:53 AM2/6/09
to
Gregor Kofler pisze:

In some cases (for example setAttribute("style","") not working
properly), it is really a problem with the setAttribute, but generally
works in IE:

http://www.quirksmode.org/dom/w3c_core.html

--
Peter

Thomas 'PointedEars' Lahn

unread,
Feb 6, 2009, 11:37:24 AM2/6/09
to
Peter May wrote:
> Gregor Kofler pisze:
>> Peter May meinte:
>>>> Never use setAttribute() if an shorthand property would do.
>>>>
>>>> linkElement.type = ...;
>>>> linkElement.href = ...;
>>> Why?
>> Most of the time it's just superfluous (and I assume slower). Anyway,
>> google for "internet explorer setattribute problem".
>
> In some cases (for example setAttribute("style","") not working
> properly),

"Not properly" as in ...?

> it is really a problem with the setAttribute,

The example would create a document tree that is _not_ Valid; the `style'
attribute value of HTML elements must not be the empty string. If that
doesn't work (i.e. does nothing or throws an exception), it is *correct*.
If it does something else, that would be a bug.

> but generally works in IE:

Well, no.

> http://www.quirksmode.org/dom/w3c_core.html

You did not read that document thoroughly enough.


PointedEars

vunet

unread,
Feb 6, 2009, 12:41:43 PM2/6/09
to
On Feb 6, 11:37 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

So what potential problems will I come across when loading some
libraries with this approach:

try{
var script = document.createElement("script");
script.src = libraryName;
script.type = "text/javascript";
script.language = "JavaScript";
script.defer = true;
var heads = document.getElementsByTagName("head");
heads[0].appendChild(script);
}catch(e){
//inserting via DOM fails in Safari 2.0
document.write('<script type="text/javascript" src="'+libraryName
+'"><\/script>');
}

Gregor Kofler

unread,
Feb 6, 2009, 5:44:57 PM2/6/09
to
Peter May meinte:
Why should I use something that *might* work, if there is an alternative
available without any problems? As far as I can remember, I haven't been
in the need of using setAttribute().

Gregor

David Mark

unread,
Feb 6, 2009, 6:00:41 PM2/6/09
to

You don't need it or getAttribute at all for most HTML-based
applications. Last time I had to use them was on an SVG project. And
yes, those methods are broken as designed in IE.

The style example is equivalent to this in IE;

el.style = '';

Another example:

el.setAttribute('for', 'myid');

is equivalent to:

el.for = 'myid';

IE simply sets the property with the supplied string, which is wrong
in many cases.

Hopefully MS will figure out attributes ten years later in v8, but
these methods will still be unneeded.

Thomas 'PointedEars' Lahn

unread,
Feb 7, 2009, 5:06:38 AM2/7/09
to
Martin Rinehart wrote:
> Thomas 'PointedEars' Lahn

wrote:
> > Probably not. For a start, it doesn't work reliably in Netscape 4.x
> > due to
> > the NRLB.
>
> Were you being serious or sarcastic?

You have destroyed the context of my statement. Learn to quote.

I was serious. Netscape 4.x are the newest versions of the reference
implementation (JavaScript 1.0 and document.write() were introduced in
Netscape 2.0) that still can run (and runs) on current machines and
works with a lot of Web sites.


HTH

PointedEars

Peter May

unread,
Feb 9, 2009, 5:07:49 AM2/9/09
to
Thomas 'PointedEars' Lahn pisze:

> Peter May wrote:
>> Gregor Kofler pisze:
>>> Peter May meinte:
>>>>> Never use setAttribute() if an shorthand property would do.
>>>>>
>>>>> linkElement.type = ...;
>>>>> linkElement.href = ...;
>>>> Why?
>>> Most of the time it's just superfluous (and I assume slower). Anyway,
>>> google for "internet explorer setattribute problem".
>> In some cases (for example setAttribute("style","") not working
>> properly),
>
> "Not properly" as in ...?

According to the table http://www.quirksmode.org/dom/w3c_core.html
setAttribute is generally, but incomplete implemented. I understand it
so that it works, but not in every case.

>> it is really a problem with the setAttribute,
>
> The example would create a document tree that is _not_ Valid; the `style'
> attribute value of HTML elements must not be the empty string. If that
> doesn't work (i.e. does nothing or throws an exception), it is *correct*.
> If it does something else, that would be a bug.
>
>> but generally works in IE:
>
> Well, no.

You can always use some alternative solution. Attraction:
http://www.peterbe.com/plog/setAttribute-style-IE

>> http://www.quirksmode.org/dom/w3c_core.html
>
> You did not read that document thoroughly enough.

It's possible.

--
Peter

David Mark

unread,
Feb 9, 2009, 5:18:12 AM2/9/09
to
On Feb 9, 5:07 am, Peter May <peter....@poczta.fm> wrote:
> Thomas 'PointedEars' Lahn pisze:
>
> > Peter May wrote:
> >> Gregor Kofler pisze:
> >>> Peter May meinte:
> >>>>> Never use setAttribute() if an shorthand property would do.
>
> >>>>>   linkElement.type = ...;
> >>>>>   linkElement.href = ...;
> >>>> Why?
> >>> Most of the time it's just superfluous (and I assume slower). Anyway,
> >>> google for "internet explorer setattribute problem".
> >> In some cases (for example setAttribute("style","") not working
> >> properly),
>
> > "Not properly" as in ...?
>
> According to the tablehttp://www.quirksmode.org/dom/w3c_core.html

> setAttribute is generally, but incomplete implemented. I understand it
> so that it works, but not in every case.
>
> >> it is really a problem with the setAttribute,
>
> > The example would create a document tree that is _not_ Valid; the `style'
> > attribute value of HTML elements must not be the empty string.  If that
> > doesn't work (i.e. does nothing or throws an exception), it is *correct*.
> > If it does something else, that would be a bug.
>
> >> but generally works in IE:
>
> > Well, no.
>
> You can always use some alternative solution. Attraction:http://www.peterbe.com/plog/setAttribute-style-IE

You don't need an alternative solution as you can use DOM properties
for virtually everything (at least in HTML documents.)

From that article:

function _setStyle(element, declaration) {
if (declaration.charAt(declaration.length-1)==';')
declaration = declaration.slice(0, -1);
var k, v;
var splitted = declaration.split(';');
for (var i=0, len=splitted.length; i<len; i++) {
k = rzCC(splitted[i].split(':')[0]);
v = splitted[i].split(':')[1];
eval("element.style."+k+"='"+v+"'");

}
}

Now, if the author had bothered to research something other than
quirksmode.org (cited as a "brilliant" page for noting that IE's
implementation is "incomplete"), he could have skipped writing the
article.

el.style.cssText = ...

[snip]

Peter May

unread,
Feb 9, 2009, 5:27:16 AM2/9/09
to
David Mark pisze:
[...]

> You don't need an alternative solution as you can use DOM properties
> for virtually everything (at least in HTML documents.)

I agree.

> From that article:
>
> function _setStyle(element, declaration) {
> if (declaration.charAt(declaration.length-1)==';')
> declaration = declaration.slice(0, -1);
> var k, v;
> var splitted = declaration.split(';');
> for (var i=0, len=splitted.length; i<len; i++) {
> k = rzCC(splitted[i].split(':')[0]);
> v = splitted[i].split(':')[1];
> eval("element.style."+k+"='"+v+"'");
>
> }
> }
>
> Now, if the author had bothered to research something other than
> quirksmode.org (cited as a "brilliant" page for noting that IE's
> implementation is "incomplete"), he could have skipped writing the
> article.
>
> el.style.cssText = ...

Yes. It should be noted, however, that sometimes are inquisitive coders,
solutions and who are probably only do it for ideas.

--
Peter

David Mark

unread,
Feb 9, 2009, 5:38:45 AM2/9/09
to

Nothing wrong with that, but why do so many of them feel the need to
post them on the Internet, where they could have found the real
answers if they had bothered to look. These ersatz solutions get
copied and pasted by developers who don't know any better.

Peter May

unread,
Feb 9, 2009, 6:07:12 AM2/9/09
to
David Mark pisze:
[...]

> Nothing wrong with that, but why do so many of them feel the need to
> post them on the Internet, where they could have found the real
> answers if they had bothered to look. These ersatz solutions get
> copied and pasted by developers who don't know any better.

The real answer in the programming time is difficult to determine.
However, this is the internet, we have a lot of data that must be
something meaningful for you to find ;-)

--
Peter

Thomas 'PointedEars' Lahn

unread,
Feb 9, 2009, 9:28:20 AM2/9/09
to
vunet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Peter May wrote:
>>> Gregor Kofler pisze:
>>>> Peter May meinte:
>>>>>> Never use setAttribute() if an shorthand property would do.
>>>>>> linkElement.type = ...;
>>>>>> linkElement.href = ...;
>>>>> Why?
>>>> Most of the time it's just superfluous (and I assume slower). Anyway,
>>>> google for "internet explorer setattribute problem".
>>> In some cases (for example setAttribute("style","") not working
>>> properly),
>> [...]

>>> it is really a problem with the setAttribute,
>> The example would create a document tree that is _not_ Valid; the `style'
>> attribute value of HTML elements must not be the empty string. If that
>> doesn't work (i.e. does nothing or throws an exception), it is *correct*.
>> If it does something else, that would be a bug.
>>
>>> but generally works in IE:
>> Well, no.
>>
>>> http://www.quirksmode.org/dom/w3c_core.html
> You did not read that document thoroughly enough.
> [...]

Trim your quotes to the relevant parts, please.

> So what potential problems will I come across when loading some
> libraries with this approach:
>
> try{

Won't work without support for exception handling.

> var script = document.createElement("script");

Won't work without support for W3C DOM Level 1+ Core.

> script.src = libraryName;

Have you escaped characters in the value of `libraryName' that must not be
part of a URI before?

> script.type = "text/javascript";
> script.language = "JavaScript";

The `language' attribute is deprecated and superfluous, and so is the
corresponding property.

> script.defer = true;

AFAIK `defer' is only supported by MSHTML-based UAs, and so would the
corresponding property.

> var heads = document.getElementsByTagName("head");

Won't work without support for W3C DOM Level 2 HTML. Might fail because
HTML is case-insensitive (an underappreciated fact, even by me).

> heads[0].appendChild(script);

Might fail if there is no `head' element in the markup. Fails without
support for W3C DOM Level 1+ Core.

> }catch(e){

See `try'.

> //inserting via DOM fails in Safari 2.0

I was not aware of that issue since I'm not testing with Safari 2.0
frequently. Can you provide a test case?

> document.write('<script type="text/javascript" src="'+libraryName
> +'"><\/script>');

Won't be executed without support for exception handling. Will break in NN4
and implementations based on that because of the NLRB. Might not load the
script anyway.

Have you escaped characters that must not be part of a URI before? In
contrast to the possibility with the property assignment, no DOM
implementation will do that for you here.

> }

You could have indented the example a bit less, so that it does not exceed
80 characters per line. RTFFAQ: <http://jibbering.com/faq/#posting>


PointedEars

kangax

unread,
Feb 9, 2009, 12:22:39 PM2/9/09
to
Thomas 'PointedEars' Lahn wrote:
> vunet wrote:
[...]

>> var heads = document.getElementsByTagName("head");
>
> Won't work without support for W3C DOM Level 2 HTML. Might fail because
> HTML is case-insensitive (an underappreciated fact, even by me).

Are there any clients out there which you observed failing? Or is it a
purely theoretical point?

[...]

>> //inserting via DOM fails in Safari 2.0
>
> I was not aware of that issue since I'm not testing with Safari 2.0
> frequently. Can you provide a test case?

AFAIK, setting `text` property of a script element also fails in Safari
2.x. Here's a minimal test case that "fails" in v. 2.0 - 2.0.4 (Mac OSX
10.5.6)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
var scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.text = 'alert(1)';
var headEl = document.getElementsByTagName('head')[0];
headEl.appendChild(scriptEl);
</script>
</body>
</html>

Interestingly, the issue can be circumvented in versions 2.0.2, 2.0.3
and 2.0.4 by appending textNode, rather than setting `text` property:

...
var scriptEl = document.createElement('script');
scriptEl.type = 'text/javascript';
scriptEl.appendChild(document.createTextNode('alert(1)'));
var headEl = document.getElementsByTagName('head')[0];
headEl.appendChild(scriptEl);
...

Safari 2.0 doesn't "like" even this "workaround".

Setting `src` doesn't work in 2.0 either (but works as expected in 2.0.2
- 2.0.4)

--
kangax

Thomas 'PointedEars' Lahn

unread,
Feb 9, 2009, 2:20:17 PM2/9/09
to
kangax wrote:
> Thomas 'PointedEars' Lahn wrote:
>> vunet wrote:
>>> var heads = document.getElementsByTagName("head");
>> Won't work without support for W3C DOM Level 2 HTML. Might fail because
>> HTML is case-insensitive (an underappreciated fact, even by me).
>
> Are there any clients out there which you observed failing?

As for the former: yes, definitely. As for the latter: no, but I have not
done quite enough testing yet.

> Or is it a purely theoretical point?

So far, yes, which is what the "might" was intended to indicate.

>>> //inserting via DOM fails in Safari 2.0
>> I was not aware of that issue since I'm not testing with Safari 2.0
>> frequently. Can you provide a test case?
>
> AFAIK, setting `text` property of a script element also fails in Safari
> 2.x. Here's a minimal test case that "fails" in v. 2.0 - 2.0.4 (Mac OSX
> 10.5.6)

> [...]

Thanks, I'll look into that later.


PointedEars

SAM

unread,
Feb 9, 2009, 4:34:34 PM2/9/09
to
Le 2/9/09 6:22 PM, kangax a écrit :

>
> AFAIK, setting `text` property of a script element also fails in Safari
> 2.x. Here's a minimal test case that "fails" in v. 2.0 - 2.0.4 (Mac OSX
> 10.5.6)

Could you tell me how to do to install a Safari.2 on Mac OSX 10.5 ?
(where to find it at Apple ?)

--
sm

SAM

unread,
Feb 9, 2009, 5:18:40 PM2/9/09
to
Le 2/9/09 10:34 PM, SAM a écrit :

I found it:
<http://michelf.com/projets/multi-safari/>

--
sm

Reply all
Reply to author
Forward
0 new messages