Not Overwriting window.onload

July 3, 2007

One of the things that has bugged me for a long time with JavaScript is how to deal with a large web site system with multiple JavaScript libraries written by various different authors at different skill levels. Two issues come to mind right away that need to be resolved:

First, JavaScript has no concept of namespaces, so there are bound to be conflicts between libraries unless you get lucky and all your JavaScript library authors picked different function and global variable names.

Second, and perhaps more annoying, are the times when multiple, independent libraries need to set the window.onload event. When you’re writing your own application, where you are starting from scratch or are the architect, this isn’t a problem. You just design around it. If you’re building a new JavaScript central library system, this also isn’t much of a problem because you can implement a “window.onload registry” where each library that needs access to the event just pushes a function name or reference to an array. Then there’s only one library that calls window.onload, and that library executes each function in the array. Easy.

But what if you’ve got an existing site with random JavaScript libraries in various patterns across various pages? Some libraries need window.onload, but others don’t. And you now need to write a new library or two (or three) that may each need to register with window.onload, but you don’t want to overwrite existing library calls to window.onload, and you want to ensure your call doesn’t get overridden.

Well, there’s a two-part solution. For all non-stupid browsers (i.e. everyone except IE), register a DOMContentLoaded event. For the most popular stupid browser, use the <script> tag’s “defer” attribute along with a creative use of the onreadystatechange event.

Suppose you have an XHTML file like so:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <title>Page Title</title>
        <script type="text/javascript" src="script.js"></script>
    </head>
    <body>
        <h2>Page Header</h2>
        <ul id="place_to_put_stuff"></ul>
    </body>
</html>

What you want to do is have a function contained within script.js execute after page load is complete that will push some data into that empty <ul>. Of course, you could just inline all your JavaScript inside the <ul>, but that’s ugly, bad, and evil. (If you don’t know why, stop reading now and go buy a good elementary programming book like Code Complete.)

Looking at this particular example, the code in script.js is very simple:

function displayListings() {
    _buildStuff( "place_to_put_stuff", "Some stuff and things" );
    _buildStuff( "place_to_put_stuff", "More stuff and things" );
}

function _buildStuff( id, text ) {
    var li = document.createElement("li");
    li.appendChild( document.createTextNode(text) );
    document.getElementById(id).appendChild(li);
}

You just need to get the browser to run displayTVListings() at the right time but without resorting to setting window.onload. One solution is to add the following to the bottom of script.js:

if ( document.addEventListener ) {
    document.addEventListener(
        "DOMContentLoaded", displayListings, false
    );
}
else if ( document.all && ! window.opera ) {
    document.write(
        '<script type="text/javascript" id="displayListingsLoader" ' +
        'defer="defer" src="javascript:void(0)"><\/script>'
    );
    var contentLoader = document.getElementById("displayListingsLoader");
    contentLoader.onreadystatechange = function () {
        if ( this.readyState == "complete" ) displayListings();
    }
}

This will register the DOMContentLoaded event for all non-stupid browsers. For IE, you have to resort to using the “defer” attribute of the <script> tag.

I found this idea when reading a few blogs on the subject:

So that solves the window.onload problem, but what about the namespaces issue? Well, more on that in a later post.

Posted by Gryphon Shafer on July 3, 2007 2:25 PM | | Comments (0)

Post a Comment

After posting a comment, it will have to be approved before it's displayed on the site.

View from WebCam

Current View from Home

Recent Posts

Blog Categories

Archives

Syndication Feeds

Contact Information

J. Gryphon Shafer
AIM: ShaferGryphon
ICQ: 63254641
YIM: GryphonShafer
Skype: gryphon.shafer
Jabber: GryphonShafer
MSNIM: gryphonshafer
PerlMonks: gryphon
CPAN: gryphon
PGP ID: CBE9C7F0

Presentation