AXAH - Crawl before you Ajax

4 comments | Posted: 24 January 06 in Tutorials, by Cody Lindley

The ability to update content asynchronous (remote scripting/changing a web page dynamically without a browser refresh) is the mythical power behind Ajax! Whether or not you agree with this notion is not important. Let’s just assume you agree, and because you agree, it would then be fair to say that using XML to grasp the power of Ajax would not necessarily be all that pertinent. What is vital is the basic understanding of the technique used (hidden requests to the server) to update content asynchronously.

With that said, the purpose of this article is to give an overview of Ajax without the use of XML. By focusing on the asynchronous and javascript parts of Ajax, I hope to ease the learning curve typically associated with Ajax. This article will detail the javascript required to dynamically update a web page with XHTML fragments instead of XML. If you are thinking this sounds an awful lot like AHAH (Asychronous HTML and HTTP), then you would be correct. This is pretty much the AHAH method. The exception is that my technique will be called AXAH (Asychronous XHTML and HTTP). I know, semantics really. Anyhow, I don't want to draw a dividing line between XML and XHTML. In theory they are the same thing, but today we are going to think of XHTML markup as a simple text string instead of well structured XML. I'll explain in a minute, but first let's have a look at our very simple demo or you can download the files for viewing on your own server. Make sure you are familiar with the source code for this demo before you proceed (a simple view source will do it).

If its not obvious, the example I created demonstrates how to update the content in a web page without a browser refresh. Let's take a moment and think about how simple this really is. All that is going on here is my browser is making a hidden (no visual refresh) HTTP (Hyper Text Transfer Protocol) request. Visual HTTP requests happen all the time when we surf the web using a browser. For example when I go from Yahoo.com to Google.com I 'm simply making an HTTP request for a new URL. The browser makes the request (because you load the new URL somehow), the URL changes, and the browser changes by removing the current content from a prior request and replacing it with the newly requested content. Of course this is all done over HTTP. With JavaScript making this type of request can be accomplished seamlessly (No visual browser re-fresh). Using a JavaScript object, a hidden HTTP request can retrieve new content (usually in the form of a text string or XML) in the background. Once the JavaScript has the requested information, it can then be manipulated and added to the current content by using the Document Object Model. If I lost you with my last couple of statements you might want to spend sometime brushing up on the basics of JavaScript and the DOM.

With the 50 thousand foot view of the AXAH technique under our belt, let's jump straight into the JavaScript and have a look at the event that starts the hidden HTTP request in my simple demo. In my particular example I have foregone the use of unobtrusive JavaScript by adding an onclick event to the <a> element (unobtrusive techniques have been ignored for the sake of clarity). When you click on a link in the example the javascipt function getAXAH(); is called/executed. The function has two arguments, "URL" and "elementContainer". The "URL" is the location of the content on the server the HTTP request is trying to access. In this example we are providing a URL to a specific xhtml document located on the server. The "elementContainer" argument is the value of an ID attribute on a specific element in the current content where the new content should be encapsulated. In my example I'm using a <div> element with an id attribute value of "content." Below is the <a> element from my example that will load the bold, blue Lorem Ipsum text:

<a href="Lorem-ipsum-blue.htm" onclick="getAXAH('Lorem-ipsum-blue.htm','content');return false;">
Load blue Lorem Ipsum <strong>bold</strong> text
</a>

Now that we understand how the getAXAH(); is called, and what parameters are passed to the function let's have a look at the function itself:

function getAXAH(url,elementContainer){
    document.getElementById(elementContainer).innerHTML = '<blink class="redtxt">Loading...<\/blink>';
    var theHttpRequest = getNewHttpObject();
    theHttpRequest.onreadystatechange = function() {processAXAH(elementContainer);};
    theHttpRequest.open("GET", url);
    theHttpRequest.send(false);

        function processAXAH(elementContainer){
           if (theHttpRequest.readyState == 4) {
               if (theHttpRequest.status == 200) {
                   document.getElementById(elementContainer).innerHTML = theHttpRequest.responseText;
               } else {
                   document.getElementById(elementContainer).innerHTML="<p><span class='redtxt'>Error!<\/span> HTTP request return the following status message: " + theHttpRequest.statusText +"<\/p>";
               }
           }
        }
}

The first statement found inside the function locates the element using the getElementById(); method by crawl the DOM to find the element with the correct ID. Once we find the correct element, the innerHTML property can be reset by giving it a new value. In the case of our function I am giving a new string value which contains XHTML. The innnerHTML property will essentially replace all markup and content with a given element. In our case, the given element is a <div> element.

On the next line I am creating a new variable (theHttpRequest) with a value that is returned by the getNewHttpObject(); function. Since we are calling a function from within another function let's have a look at that function before we proceed.

function getNewHttpObject() {
    var objType = false;
    try {
        objType = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
        try {
            objType = new ActiveXObject('Microsoft.XMLHTTP');
        } catch(e) {
            objType = new XMLHttpRequest();
        }
    }
    return objType;
}

The getNewHttpObject(); has one purpose, return the appropriate object type for doing an HTTP request based on which browser the user has. We have to do this because Microsoft has yet to give support for the XMLHttpRequest object that most modern browsers use today. In fact there are two implementations from Microsoft (Msxml2.XMLHTTP and Microsoft.XMLHTTP). The getNewHttpObject(); uses the different objects themselves to detect which browser the user has and then return that particular object type to the getAXAH(); function. This is really silly, but we can't ignore the fact that the majority of people on the web still use Internet Explorer. Due to this, we need an extra function that determines the appropriate object based on browser. Now lets look at the getAXAH(); function again.

With the correct object stored in the "theHttpRequest" variable we can use the common methods, properties and events associated with the various HTTP request objects. For instance, on the next line of the getAXAH(); function we use the "theHttpRequest" variable (storing the request object type) to set the "onreadystatechange" event for that object. This event is fired each time the status of the object changes. You can even access the status of the current state with this property, but more on that in a minute. Just keep it in mind that when the onreadystatechange event occurs the processAXAH(); is invoked.

Now that we have set what happens on a state change, let's move to the next line. Here we invoke the open(); method for our request object. This method sets up the call to the server. Several parameters (5 total, 2 required and 3 optional) can be used here but we are only using two. The first argument is the the type of request (GET, POST, or PUT) being made. The second argument is the URL of the resource we are requesting. In my code, this parameter is being set by a parameter passed from the getAXAH(); function. The next line of code actually sends the request. The argument used with the send(); method is set to false because we are not sending any content with our request, we are only requesting information.

If you remember back to the onreadystatechange event, you will see that I assigned a function to this event. This function is processAXAH(); and includes our "elementContainer" as a parameter. In other words I reused the "elementContainer" parameter in our embedded function. I am passing the same parameter in the getAXAH(); function right on to the processAXAH(); function embedded in the getAXAH(); function.

Looking at the getAXAH(); function it should be clear (if I haven't made it clear yet) that each time the onreadystatechange event is fired the getAXAH(); function is also executed. The getAXAH(); function purpose is to check the ready state of the request and the http status code return from the server. Looking at the function you will see that the first statement inside the function is checking if the readystate is equal to 4. The readystate has five possible values (0=uninitializewd, 1=loading, 2=loaded, 3=interactive, 4=complete), but due to cross browser compatibility we are only concerned with a complete value (4=complete). So we check to see if the state has a value equal to 4, and if it does, we then check to see if the http request status returned by the server is equal to 200. This 200 status value simply means that the http status is ok and the information was found. If you provided the wrong information in the URL parameter or don't have the file the request is looking in the correct location the http request status will likely return a 404 error. A 404 server status means the request content could not be found. In the code I have written the javascript so that if the status value is anything but a 200 status error a error message is added to the page via the dom. If the status of the server returns a 200 value we then take the requested content and update our content <div> with the content found in one of the XHTMLdocuments on the server. This is done by that statement shown below.

document.getElementById(elementContainer).innerHTML = theHttpRequest.responseText;

Notice that we are traversing the DOM with the getElementById(); method to find the <div> with an Id value of "content" (elementContainer is a parameter that represents the string "content") and then setting the innerHTML property of that particular element with the content requested. The content requested is accessible from the responseText property of the request object. Had we been working with XML today the response property would have been responseXML instead of responseText. To show how simple remote scripting is I have chosen to update my page with a simple text string, and thus I am using the responseText property to return the information as a text version instead of an XML object. Our text string just so happens to also be valid XHTML. So when we append this string of text back into the page using the DOM the browser also parses the tags inside the text string. Had we used the responseXML property extrapolating the information sent back from the server would have been much more complicated depending upon how the information is used. And with that said, we have successfully updated our page with a hidden JavaScript call to the server. Really pretty easy, don’t you think?

With a basic knowledge of the AXAH technique firmly understood I think a person could reasonably be expected to grasp more complex Ajax examples. So if, and when, you think you're ready here are a couple of Ajax examples to get you rolling.

Discuss This Topic

  1. 1 RodeoClown

    Just a quick note, MS announced they will have a native XMLHTTPRequest object in IE7 (but you’ll still need the selection code to support IE6 :S)

     
  2. 2 Matt Heerema

    Thanks Cody! Extremely helpful and timely for me :)

     
  3. 3 Yannick

    Cody, many thanks for this wonderful article. As Matt said it was extremely helpful. It definitely gave me a better understanding of the concept and was simple enough for me to follow each step of the way.

     
  4. 4 Jonathan

    This is a great example. I find that most of the time XML is used in AJAX-based applications simply because it’s XML. The reality is that for simple (and even some quite complicated) applications, XML isn’t really necessary. Returning XHTML code instead of an XML tree that needs to be parsed by JavaScript is usually easier for people to understand, and requires less processing.

    This is just my opinion though, and I’m not saying that XML isn’t necessary in all cases, because there are many examples of when it can be useful, such as passing a very large amount of data back to the client (think gmail).

     

Comments closed after 2 weeks.