spacer

Webref WebRef   Sitemap · Experts · Tools · Services · Newsletters · About i.com

home / programming / javascript / domwrapper To page 1To page 2To page 3current pageTo page 5
[previous] [next]

A Cross-Browser DOM Document Wrapper

Developer News
News Flash: Adobe Has iPhone Workaround
Adobe's Flash 10.1 Goes Mobile (Minus iPhone)
A Salute to Visionary CEOs

The readyState Attribute and onreadystatechange Event

As mentioned earlier, there is a load() method on the DOM Document in both IE and Mozilla that allows the developer to load an XML file directly into the DOM Document. Naturally, there also must be a way to determine when the XML file has been fully loaded. As usual, IE and Mozilla take different approaches to this.

In IE, the DOM Document has a readyState attribute. The readyState attribute is an integer value indicating what the current state of loading is. These values are:

CodeStringDescription
0uninitializedThe DOM Document has been created, but the load() method has not yet been called.
1loadingThe load() method has been called and is executing.
2loadedLoading is complete, the DOM Document is now parsing the file.
3interactiveSome of the XML data has been parsed, the DOM Document is now available, but is incomplete and read-only.
4completedThe XML data has been fully parsed and the DOM Document is available in its entirety.

In addition, IE also provides a readystatechange event that can have an event handler assigned to it. Every time the readyState attribute changes, the readystatechange event fires. So, if you assign a function to the onreadystatechange event handler, you can easily see if the DOM Document is done loading.

Switching back to Mozilla for a moment, their approach is totally different, if not a bit more logical. Mozilla fires a load event when the DOM Document is done loading. So, by assigning the onload event handler, you can be alerted when the DOM Document is completely loaded. This differs from IE's method in that there are not various states of loading: the DOM Document is either loaded or it is not, and there is no attribute to tell you this. Once again, it is our job to tame Mozilla to behave more like IE.

First, we will add the readyState attribute to the Document class and initialize it to 0:

Document.prototype.readyState = "0";

Now comes the interesting challenge. There are five possible values of readyState. We know that we can simulate the first, 0, because nothing has happened. Which of the others can we simulate? Looking it over quickly, two of the remaining four are doable.

If we can listen in on the load() method, we can set the readyState value to 1 just before it executes. Also, when the Mozilla load event is fired, we can change the readyState to 4. For 2 and 3 there's just no way of knowing this information at the present time.

Let's begin with the task of "listening in" on the load() method. Of course, there is no way to actually do that. What we need to do is save the original load() method into another variable, then define our own load() method that changes the readyState attribute and then calls the original method. Sound confusing? Let's break it down:

First, save a reference to the current load() method into a "hidden" __load__ attribute:

Document.prototype.__load__ = Document.prototype.load;

Next, set the load() method to point to our own function:

Document.prototype.load = _Document_load;

Now, when someone calls load() on the Document, it will call our _Document_load() function. So let's define that function:

function _Document_load(strURL) {
 
    //change the readyState
    this.readyState = 1;
    
    //call the original load method
    this.__load__(strURL);
}

Now, when the load() method is called, the readyState will accurately change to 1. So how about when the XML has been fully loaded? This is a little bit different.

In order to change the readyState attribute to 4, we need to add an event listener to the Document's load event. This can't be done until the Document is instantiated, which means that this must be done back in the createDOMDocument() function:

    //determine if this is a standards-compliant browser like Mozilla
    if (isMoz) {
    
        //create the DOM Document the standards way
        objDOM = document.implementation.createDocument(strNamespaceURI, strRootTagName, null);    
    
        //add the event listener for the load event
        objDOM.addEventListener("load", _Document_onload, false);
        
    }

By adding this line, when the XML data has finished being loaded, it will call our _Document_onload() function, which is as follows:

function _Document_onload() {
 
    //change the readyState
    this.readyState = 4;
 
}

We can't forget about our loadXML() method. The readyState attribute also changes when it is called, so let's update our code:

    //add the loadXML() method to the Document class
    Document.prototype.loadXML = function(strXML) {
    
        //change the readystate
        this.readyState = 1;
 
        //create a DOMParser
        var objDOMParser = new DOMParser();
        
        //create new document from string
        var objDoc = objDOMParser.parseFromString(strXML, "text/xml");
        
        //make sure to remove all nodes from the document
        while (this.hasChildNodes())
            this.removeChild(this.lastChild);
            
        //add the nodes from the new document
        for (var i=0; i < objDoc.childNodes.length; i++) {
            
            //import the node
            var objImportedNode = this.importNode(objDoc.childNodes[i], true);
            
            //append the child to the current document
            this.appendChild(objImportedNode);
        
        } //End: for
        
        //change the readystate
        this.readyState = 4;
        
    } //End: function

Congratulations, we've now completed our exercise in mimicking the IE readyState attribute. Our next task: mimic the readystatechange event.

This step is actually not all that difficult. Let's assume someone wants to assign an event handler for the readystatechange event. They would do it without using IE's attachEvent() method or Mozilla's addEventListener() method. In short, they would use the old-fashioned way of assigning an event handler, as:

objDoc.onreadystatechange = myFunction;

If this is the case, then we can make an onreadystatechange attribute in Mozilla's Document class, and then just call it each time we change the readyState attribute. So, let's start by adding the attribute:

Document.prototype.onreadystatechange = null;

Next, we need to go back to the places we changed the readyState attribute and call the onreadystatechange function (if there is one). Since this may be done in several areas, we'll make a changeReadyState() function to encapsulate the functionality. The changeReadyState() function will take two parameters: the Document object to change and the value to set the readyState attribute to. Here's the code for this function:

function changeReadyState(objDOMDocument, iReadyState) {
 
    //change the readyState
    objDOMDocument.readyState = iReadyState;
    
    //if there is an onreadystatechange event handler, run it
    if (objDOMDocument.onreadystatechange != null && typeof objDOMDocument.onreadystatechange == "function")
        objDOMDocument.onreadystatechange();
}

Now, let's go and put this into the load() method and load event handler:

function _Document_load(strURL) {
 
    //change the readyState
    changeReadyState(this, 1);
    
    //call the original load method
    this.__load__(strURL);
 
}
 
function _Document_onload() {
 
    //change the readyState
    changeReadyState(this, 4);
}

We also need to update the loadXML() method that we wrote for the Document class:

    //add the loadXML() method to the Document class
    Document.prototype.loadXML = function(strXML) {
    
        //change the readystate
        changeReadyState(this, 1);
 
        //create a DOMParser
        var objDOMParser = new DOMParser();
        
        //create new document from string
        var objDoc = objDOMParser.parseFromString(strXML, "text/xml");
        
        //make sure to remove all nodes from the document
        while (this.hasChildNodes())
            this.removeChild(this.lastChild);
            
        //add the nodes from the new document
        for (var i=0; i < objDoc.childNodes.length; i++) {
            
            //import the node
            var objImportedNode = this.importNode(objDoc.childNodes[i], true);
            
            //append the child to the current document
            this.appendChild(objImportedNode);
        
        } //End: for
        
        //change the readystate
        changeReadyState(this, 4);
        
    } //End: function

With this in place, a developer has a common way to determine if a file has been loaded. When the file is finished loading, the onreadystatechange event handler is called. Within that function, you can check the value of readyState. If it is 4, then you know the file has been loaded and you are ready to roll.

A Quick Note on Loading External Files

The DOM standards support both synchronous and asynchronous loading of external XML files. Both the IE ActiveX version and the Mozilla native version support the async property on a DOM Document, such as the following:

objDOMDocument.async = true;

If async is set to false, the external XML file begins to load, but control is returned to the next line of JavaScript before the file has finished loading. If async is set to true, then control is not returned to the next line of JavaScript until the file has finished loading.

This is usually set just before loading a file, such as:

objDOMDocument.async = true;
objDOMDocument.load("myfile.xml");

home / programming / javascript / domwrapper To page 1To page 2To page 3current pageTo page 5
[previous] [next]

internet.commediabistro.comJusttechjobs.comGraphics.com

Search:

WebMediaBrands Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Shopping | E-mail Offers | Freelance Jobs

webref The latest from WebReference.com Browse >
Building a Banking Application Home Page with OOP · Mixing Scripting Languages · Review: phpFox, a Social Networking CMS with all the Bells and Whistles
Sitemap · Experts · Tools · Services · Email a Colleague · Contact FREE Newsletters 
 The latest from internet.com
Enterprise 2.0: Social Networking in the Cloud · BroadSoft Marketplace Hastens Pace of Telephony Innovation · Review: HTC Hero for Sprint

Created: June 13, 2002
Revised: June 13, 2002

URL: http://webreference.com/programming/javascript/domwrapper/4.html