JavaScript Articles
XML Menu Suite
Build powerful, client-side DHTML menus using XML for data and CSS for style. No JavaScript data! No having to place list elements on every single page of your website! No plug-ins!

Dynamically Loading
External JavaScript Files

The first time I tried to dynamically load a .js file I nearly had a nervous breakdown. I had written code like this:

<script type="text/javascript">
   
function loadScript(url)
{
  document.write('<script src="', url, '" type="text/javascript"></script>');
}

loadScript(navigator.appName.indexOf("Microsoft") != -1 ? "ie_msg.js" : "ns_msg.js");

</script>

When I went to run this code I got a "Undetermined string constant" runtime error.

Why in the name of all that is good and holy in the universe was this?

I didn't get my answer until I read David Flanagan's, JavaScript: The Definitive Guide. What's happening here is that the <script> tag is being executed by the JavaScript interpreter, despite the fact that it's contained within a string. The question still remains, why did they choose a mind-bogglingly weird implementation like this? I'm going to assume it's for speed, but I want the facts. As much as I love Flanagan, I was a little disappointed that he didn't answer this question. A cursory look at the ECMAScript Language Specification didn't reveal an answer either. It might be that this behavior is a byproduct of the HTML parser. I really do not know. I will continue to investigate this matter in my spare time, which, unfortunately, is in severely short supply, and post the answer here when and if I find it. If anybody has an answer, please let me know. Also, please include references to supporting documentation. I will give you credit if you answer this elusive mystery of the universe.

Yeah-yeah, but how am I supposed to dynamically load external JavaScript files?

I'll give you two ways to dynamically load external JavaScript files. One way is what I will term as the Static Way, which JavaScript experts have been giving people since they first ventured out of their caves armed with clubs to fend off those nasty Tyrannosauruses.

The other way is what I will term as the DHTML Way — and you guessed it — it uses DHTML. As far as I know, I am the first person on the planet — perhaps even the universe (but probably not Dimension 1217.32 of Universe z540a — these guys are really sharp), to write about or use this approach. Not bad for an unemployed guy, eh? Too bad the Interdimensional Transport Authority wasn't interested in hiring me to program their Space-Time Reticulation Units.

Static Way

With the Static Way, you put an escape character before the closing </script> tag, like this: <\/script>

This is demonstrated in the example code below. What the escape character does here is prevent the unwanted behavior of the JavaScript string which contains <script> from being executed as if it were an HTML tag.

<script type="text/javascript">

function staticLoadScript(url)
{
   document.write('<script src="', url, '" type="text/JavaScript"><\/script>');
}

staticLoadScript("static_way.js");

</script>

The staticLoadScript() method in the example code above must be called while the HTML page is being created, as it uses document.write() in order to create the <script> tag which imports the external JavaScript file. If you called staticLoadScript() after the page is loaded, it would clobber the contents of the page, as document.write() would overwrite the document's HTML content.

DHTML Way

The DHTML Way is shown in the example below. With the DHTML Way, you create a new script document element and append it to the document.

<script type="text/javascript">

function dhtmlLoadScript(url)
{
   var e = document.createElement("script");
   e.src = url;
   e.type="text/javascript";
   document.getElementsByTagName("head")[0].appendChild(e);
}

onload = function()
{
   dhtmlLoadScript("dhtml_way.js");
}

</script>

The dhtmlLoadScript() method in the example code above, unlike the staticLoadScript() method of the previous example, can be called at any time during program execution, yet it is required that the document be at least partially loaded before it is called. In the example code, I can be assured that the document is loaded when dhtmlLoadScript() is called, because I call it in the onload handler, which doesn't get called until the document is loaded.

Summary

I've included a demo which you can download here. The demo uses both the Static and DHTML approaches to load external JavaScript files.

After looking at the source code for both ways of loading external JavaScript files, you might say to yourself, "The Static Way has much less source code. It therefore must be better." Well, as they say, it's not the size, it's the technique that counts. The source code for staticLoadScript(), while shorter, is actually harder to read than the source code for dhtmlLoadScript(). It also would be harder to modify, as you would have to contend with its nasty strings which have quotes inside of them.

Caveats

The dhtmlLoadScript() method in the example above will only work with browsers that support dynamically adding elements to a page using the DOM (Document Object Model.) This means that this method will not work on versions of Netscape below 6. I don't consider this a real problem as I don't think that anyone in their right mind should be supporting these ancient, obsolete browsers unless they have a terribly good reason to do so. What I do consider to be a problem is that the current Opera browser — at the time of this writing it is version 6.04, doesn't support dynamically adding elements to a page. This means that the dhtmlLoadScript() won't work with the current version of Opera.

I have no doubts that Opera will eventually fully support the DOM. The question is when. Opera's lack of support for DHTML continues to give me a real pain in the ass. These people really need to get their act together.

References

"ECMAScript Language Specification", Standard ECMA-262, 3rd Edition - December 1999.

"JavaScript: The Definitive Guide, Fourth Edition" by David Flanagan. Published by O'REILLY®. ISBN: 0-596-0048-0 (Page 188, Section 12.2.1.2)

Written by: Moshe Moskowitz