Implementing Our Library

Having identified what needs to be done, we'll now put together a more capable Ajax library.

Creating XMLHTTPRequest Instances

Let's turn our attention first to the routine for creating instances of the XMLHTTPRequest object.

Currently this function is coupled tightly with the routine for constructing and sending HTTP GET requests. Let's decouple the part responsible for the creation of the XMLHTTPRequest instance and put it into a function of its own:

function createREQ() {
try {
     req = new XMLHttpRequest(); /* e.g. Firefox */
     } catch(err1) {
     try {
     req = new ActiveXObject("Msxml2.XMLHTTP");
     /* some versions IE */
     } catch (err2) {
       try {
       req = new ActiveXObject("Microsoft.XMLHTTP");
       /* some versions IE */
       } catch (err3) {
        req = false;
       }
     }
   }
   return req;
}

 

We can now create XMLHTTPRequest object instances by simply calling the following function:

var myreq = createREQ();

 

HTTP GET and POST Requests

We'll start with the GET request because we already support that type of request:

function requestGET(url, query, req) {
myRand=parseInt(Math.random()*99999999);
req.open("GET",url+'?'+query+'&rand='+myRand,true);
req.send(null);
}

 

To this request we must pass as arguments the URL to which the request will be sent and the identity of the XMLHTTPRequest object instance.

We could exclude the query argument because, in a GET request, it's encoded into the URL. We keep the two arguments separate here to maintain a similar interface to the function for making POST requests.

The query argument must be suitably encoded prior to calling the function, though the cache-busting random element is added by the function.

Next, the POST function:

function requestPOST(url, query, req) {
req.open("POST", url,true);
req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
req.send(query);
}

 

The Callback Function

How do we deal with the callback function? We are going to add a further function:

function doCallback(callback,item) {
eval(callback + '(item)');
}

 

This function uses JavaScript's eval() function to execute another function whose name is passed to it as an argument, while also passing to that function an argument of its own, via item.

Let's look at how these functions might interact when called from an event handler:

function doAjax(url,query,callback,reqtype,getxml) {
// create the XMLHTTPRequest object instance
var myreq = createREQ();
myreq.onreadystatechange = function() {
if(myreq.readyState == 4) {
   if(myreq.status == 200) {
     var item = myreq.responseText;
     if(getxml==1) {
        item = myreq.responseXML;
      }
    doCallback(callback, item);
    }
  }
}
if(reqtype=='post') {
requestPOST(url,query,myreq);
} else {
requestGET(url,query,myreq);
}
}

 

Our function doAjax now takes five arguments:

 

Listing 17.2 shows the complete JavaScript source code.

Listing 17.2. The Ajax Library myAJAXlib.js

 

 

function createREQ() {
try {
     req = new XMLHttpRequest(); /* e.g. Firefox */
     } catch(err1) {
       try {
       req = new ActiveXObject('Msxml2.XMLHTTP'); /* some versions IE */
       } catch (err2) {
         try {
         req = new ActiveXObject("Microsoft.XMLHTTP"); /* some versions IE */
         } catch (err3) {
          req = false;
         }
       }
     }
     return req;
}
function requestGET(url, query, req) {
myRand=parseInt(Math.random()*99999999);
req.open("GET",url+'?'+query+'&rand='+myRand,true);
req.send(null);
}
function requestPOST(url, query, req) {
req.open("POST", url,true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(query);
}
function doCallback(callback,item) {
eval(callback + '(item)');
}

function doAjax(url,query,callback,reqtype,getxml) {
// create the XMLHTTPRequest object instance
var myreq = createREQ();

myreq.onreadystatechange = function() {
if(myreq.readyState == 4) {
   if(myreq.status == 200) {
      var item = myreq.responseText;
      if(getxml==1) {
         item = myreq.responseXML;
      }
      doCallback(callback, item);
    }
  }
}
if(reqtype=='post') {
requestPOST(url,query,myreq);
} else {
requestGET(url,query,myreq);
}
}