Ajax From Scratch

Page Updated: Mon, 23 Sep 2019 23:40 AEST (UTC+1000)

Here we will go through the core technical steps to implement Ajax.

Our goal will be to display parts of an XML file as an XHTML table within the current page.

We will achieve this by using Javascript to make an asynchronous call to retrieve the XML file from the server. This will be done through browser specific objects that enable server communication. These will be cast into a variable that can be handled cross browser. We can think, then, of "a XHR object". Once we have retrieved the XML file we will traverse it using the DOM to build the XHTML table. Lastly we insert the newly created table into the page.

The example code below will contain all that is needed for the demo at the end of the page. To see the code that actually does the job use your browsers' View > Source command to look at the code in the <head> section of this page.

The example code below is simplified. In production you will want to employ a robust, cross browser, and easy to use AJAX library. A good library is Ajax Toolbox by Matt Kruse. A list of libraries can be found at Ajax Patterns > Javascript Remoting Frameworks, a wiki by Michael Mahemoff.

The XML file

We start with a simple XML file.

<?xml version="1.0"?>
<aircraft>
  <type code="B734">
    <manufacturer>Boeing</manufacturer>
    <model>737-400</model>
    <seats>168</seats>
    <engineType>jet</engineType>
    <ceiling>37000</ceiling>
  </type> 
  <type code="BE58">
    <manufacturer>Beechcraft</manufacturer>
    <model>Baron 58</model>
    <seats>6</seats>
    <engineType>propeller</engineType>
    <ceiling>20688</ceiling>
  </type> 
  ...           
</aircraft>

Create the XHR object

Using Javascript as our programming language we create a particular object within the DOM that enables communication with the server. This will be XMLHttpRequest for gecko based browsers and others, eg Firefox, or XMLHTTP for Microsoft Internet Explorer.

We use the cross browser technique, object detection, to determine which of these objects we want. We name whichever object as XHR. From then on we can treat it in a browser independent way.

/* Globals */
Xhr = ajaxCreateXhr();

function ajaxCreateXhr() { 
  var xhr;
  try {
    if (window.XMLHttpRequest) { // Mozilla, Safari,...
      xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
      xhr = new ActiveXObject("Msxml2.XMLHTTP");
    }
  } catch (e) {
    var errorMessage = "Your browser does not support the creation"
        + "of an XHR instance.";
    throw new Error(errorMessage);          
    return false;
  }
  return xhr;
}

The Asynchronous Call

Next we make an a asynchronous call to retrieve the XML file. An asynchronous call allows other code to continue executing while the data request goes on it's journey to and from the server. In order for the code to know when that journey has ended we assign a function the to Xhr.onreadystatechange

function ajaxSendRequest(url) {
  Xhr.onreadystatechange = ajaxHandleResponse;
  try {
    Xhr.open('GET', url, true); // True for asynchronous call.
    Xhr.send(null);
  } catch (error) {
    var errorMessage = "There was a problem retrieving the XML data. "
        + "\nFirst, Try running from a web server, eg http://localhost," 
        + "rather than file system.\n" 
        + "XMLHttpRequest Error Message: \n" 
        + ((Xhr.statusText == "") ? "" : "statusText " + Xhr.statusText);
    throw new Error(errorMessage);
    return false;
  }      
}        

Handling the Sever Response

ajaxHandleResponse() is called after the data request has returned from the server. This simply passes execution to a "success" function if no problems arise.

function ajaxHandleResponse() {
  var readyStateCode = {
        Completed:4
      };

  var httpStatusCode = {
        Ok:200 // The request has succeeded  
      };   
  
  if (Xhr.readyState == readyStateCode.Completed) {
    if (Xhr.status == httpStatusCode.Ok) {
      ajaxOnSuccess();
    } else {
      var errorMessage = ""
      errorMessage = "There was a problem with the response. \n";
      errorMessage += "HTTP Request Status Code: " + Xhr.status + "\n";
      errorMessage += "HTTP Request Status Text: " + Xhr.statusText;
      throw new Error(errorMessage);
      return false;
    }
  }      
}

Using A Successful Response

The ajaxHandleResponse() function passes execution to ajaxOnSuccess(). We handle the successful response according to the specifics of our application. In this example, somewhat typical, we use the DOM to traverse the XML now stored in the XHR object. We create the XHTML table as we traverse the DOM. Then we insert the table into our desired place in the current web page.

function ajaxOnSuccess() {
  var xmlDomDocument = Xhr.responseXML; 
  
  // Application Specific Code Bellow  
  var xhtmlString = "";
  var memberChildren;
  var nodeType = new Object();
  nodeType.element = 1;
  
  xhtmlString += "<table ID="Table1">";
  xhtmlString += "<thead><tr>";
  xhtmlString += "<td>Manufacturer<\/td>";
  xhtmlString += "<td>Model<\/td>";
  xhtmlString += "<td>Seats<\/td>";
  xhtmlString += "<td>Engine Type<\/td>";
  xhtmlString += "<td>Ceiling<\/td>";
  xhtmlString += "<\/tr><\/thead>";
  xhtmlString += "<tbody>";
  var members = xmlDomDocument.getElementsByTagName("type");
  
  for (var i = 0; i < members.length; i++) {
    xhtmlString += "<tr>";
    memberChildren = members[i].childNodes;
    for (var j = 0; j < memberChildren.length; j++){
      if (memberChildren[j].nodeType == nodeType.element) {
        xhtmlString += "<td>" + memberChildren[j].firstChild.nodeValue + "<\/td>";
      }
    }
    xhtmlString += "<\/tr>";
  }
  xhtmlString += "<\/tbody>";
  xhtmlString += "<\/table>";
  
  // Insert into the web page.
  document.getElementById("output").innerHTML = xhtmlString;      
}

Kick the whole thing off

Initiating the Asynchronous call:

function startAjax(){
  ajaxSendRequest("aircraft.xml");
}

Demo

Tested in IE 5.0, IE 6.0 and Firefox 1.5. Under windows.