XMLHttpRequest, version 2
As in this book we do our best to combine theory and practice, before moving on to
implementing the AJAX form validation script, we’ll have another quick look at our
favorite AJAX object—XMLHttpRequest.
On this occasion, we will step up the complexity (and functionality) a bit and use
everything we have learned until now. We will continue to build on what has come
before as we move on; so again, it’s important that you take the time to be sure
you’ve understood what we are doing here. Time spent on digging into the materials
really pays off when you begin to build your own application in the real world.
In Chapter 2, we took a sneak peak at the XMLHttpRequest object—the nexus of
the AJAX world. Back then, we didn’t have any OOP JavaScript skills. We’ve seen
the power hidden in JavaScript in Chapter 3. In Chapter 4, we saw how PHP works
together with AJAX requests.
Our OOP JavaScript skills will be put to work improving the existing script that used
to make AJAX requests. In addition to the design that we’ve already discussed, we’re
creating the following features as well:
- Flexible design so that the object can be easily extended for future needs
and purposes - The ability to set all the required properties via a JSON object
We’ll package this improved XMLHttpRequest functionality in a class named
XmlHttp that we’ll be able to use in other exercises as well. You can see the class
diagram in the following screenshot, along with the diagrams of two helper classes:
- settings is the class we use to create the call settings; we supply an instance
of this class as a parameter to the constructor of XmlHttp - complete is a callback delegate, pointing to the function we want executed
when the call completes
The final purpose of this exercise is to create a class named XmlHttp that we can
easily use in other projects to perform AJAX calls. This class is an improvement of
the async.js script that you built in Chapter 2, JavaScript and the AJAX Client.

With our goals in mind, let’s get to it!
Time for action – the XmlHttp object
- In the ajax folder, create a folder named validate, which will host the
exercises in this chapter. - In the validate folder, create a new file named xhr.js and add the
following code to it: - To quickly test the functionality of your XmlHttp class, create a new file
named xhrtest.html and add the following code to it: - Now create async.txt with some text in it, and then load
http://localhost/ajax/validate/xhrtest.html. Figure 5-6 shows
our result:
// XmlHttp constructor can receive request settings:
// url – the server url
// contentType – request content type
// type – request type (default is GET)
// data – optional request parameters
// async – whether the request is asynchronous (default is true)
// showErrors – display errors
// complete – the callback function to call when the request
// completes
function XmlHttp(settings)
{
// store the settings object in a class property
this.settings = settings;
// override default settings with those received as parameter
// the default url points to the current page
var url = location.href;
if (settings.url)
url = settings.url;
// the default content type is the content type for forms
var contentType = “application/x-www-form-urlencoded”;
if (settings.contentType)
contentType = settings.contentType;
// by default the request is done through GET
var type = “GET”;
if(settings.type)
type = settings.type;
// by default there are no parameters sent
var data = null;
if(settings.data)
{
data = settings.data;
// if we go through GET we properly adjust the URL
if(type == “GET”)
url = url + “?” + data;
}
// by default the postback is asynchronous
var async = true;
if(settings.async)
async = settings.async;
// by default we show all the infrastructure errors
var showErrors = true;
if(settings.showErrors)
showErrors = settings.showErrors;
// create the XmlHttpRequest object
var xhr = XmlHttp.create();
// set the postback properties
xhr.open(type, url, async);
xhr.onreadystatechange = onreadystatechange;
xhr.setRequestHeader(“Content-Type”, contentType);
xhr.send(data);
// the function that displays errors
function displayError(message)
{
// ignore errors if showErrors is false
if (showErrors)
{
// display error message
alert(“Error encountered: \n” + message);
}
}
// the function that reads the server response
function readResponse()
{
try
{
// retrieve the response content type
var contentType = xhr.getResponseHeader(“Content-Type”);
// build the json object if the response has one
if (contentType == “application/json”)
{
response = JSON.parse(xhr.responseText);
}
// get the DOM element if the response is XML
else if (contentType == “text/xml”)
{
response = xhr.responseXml;
}
// by default get the response as text
else
{
response = xhr.responseText;
}
// call the callback function if any
if (settings.complete)
settings.complete (xhr, response, xhr.status);
}
catch (e)
{
displayError(e.toString());
}
}
// called when the request state changes
function onreadystatechange()
{
// when readyState is 4, we read the server response
if (xhr.readyState == 4)
{
// continue only if HTTP status is “OK”
if (xhr.status == 200)
{
try
{
// read the response from the server
readResponse();
}
catch(e)
{
// display error message
displayError(e.toString());
}
}
else
{
// display error message
displayError(xhr.statusText);
}
}
}
}
// static method that returns a new XMLHttpRequest object
XmlHttp.create = function()
{
// will store the reference to the XMLHttpRequest object
var xmlHttp;
// create the XMLHttpRequest object
try
{
// assume IE7 or newer or other modern browsers
xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older
try
{
xmlHttp = new ActiveXObject(“Microsoft.XMLHttp”);
}
catch(e) { }
}
// return the created object or display an error message
if (!xmlHttp)
alert(“Error creating the XMLHttpRequest object.”);
else
return xmlHttp;
}
<html>
<head>
<script type=”text/javascript” src=”xhr.js”></script>
</head>
<body>
<div id=”test”>
</div>
<script>
XmlHttp
({url:’async.txt’,
complete:function(xhr,response,status)
{
document.getElementById(“test”).innerHTML = response;
}
});
</script>
</body>
</html>

What just happened?
The code listed above contains significant code from the previous examples and then
some new code. Let’s break it down into small pieces and analyze it.
The chosen name for our reusable object is XmlHttp. Its functionality is wrapped in
two functions:
- XmlHttp.create(): A static method of the XmlHttp object that creates a
XmlHttpRequest object - XmlHttp(): The constructor of the XmlHttp object
From a design point of view, the XmlHttp object represents a wrapper around the
XmlHttpRequest object. The XmlHttp.create() method contains the same code that
we have previously seen in the createXmlHttpRequestObject() method. It simply
acts like a factory for an XmlHttpRequest object.
The constructor of the XmlHttp object, although it can look quite scary at first sight,
actually contains very simple code—provided that you know the theory from
Chapter 3, Object Oriented JavaScript. The constructor receives as a parameter a JSON
object containing all the settings for the XmlHttp object. Choosing a JSON object is
both convenient from the extensibility point of view and easy from the programming
point of view. We store the settings in a property with the same name.
function XmlHttp(settings)
{
// store the settings object in a class property
this.settings = settings;
The settings object contains the following properties that will be mainly used for
the XmlHttpRequest object:
- url: The URL of the AJAX request
- type: The type of the request (GET or POST)
- contentType : The content type of the request
- data: The data to be sent to the server
- async: A fl ag that specifies whether the request is synchronous or
asynchronous - complete: The function called when the request completes
- showErrors: A fl ag that indicates whether infrastructure errors will be
displayed or not
These are the parameters required to make an AJAX request. Even though the
structure and the design of this object are simple, it can be easily extended with
more advanced features, giving us the fl exibility feature we defined as a goal.
The fl exibility offered by JSON objects means we don’t force the user to pass all the
properties mentioned above each time the object is created. Instead, we created a
standard set of default values that the user can choose to overwrite when necessary.
The next few lines simply implement this logic.
Making a request through GET or POST is different and we take care of it when setting
the parameters for the request:
// by default there are no parameters sent
var data = null;
if(settings.data)
{
data = settings.data;
// if we go through GET we properly adjust the URL
if(type == “GET”)
url = url + “?” + data;
}
After having all the settings for the AJAX request, we create the XmlHttpRequest
and we open it.
// create the XmlHttpRequest object
var xhr = XmlHttp.create();
// set the postback properties
xhr.open(type, url, async);
The next step is to hook to the readystatechange event:
xhr.onreadystatechange = onreadystatechange;
The handler function is a inner function of the constructor and contains the same
code as the handleRequestStateChange() method that you already know.
Probably the most interesting piece of code is in the response handler. The
readResponse() inner function is responsible for handling the response received
from the server. It gets the content type of the response and, based on that, it builds
the response JSON object or it retrieves the response as an XML element. If no
matching content type is found, the raw text of the response is used instead.
// retrieve the response content type
var contentType = xhr.getResponseHeader(“Content-Type”);
// build the json object if the response has one
if (contentType == “application/json”)
{
response = JSON.parse(xhr.responseText);
}
// get the DOM element if the response is XML
else if (contentType == “text/xml”)
{
response = xhr.responseXml;
}
// by default get the response as text
else
{
response = xhr.responseText;
}
After gathering the necessary data, the XmlHttp object passes it all to the callback
function (settings.complete()) along with the XmlHttp object and the HTTP
response code.
// call the callback function if any
if (settings.complete)
settings.complete (xhr, response, xhr.status);
All in all, the next time you need to call a server script asynchronously from a web
page, you can count on XmlHttp to do all the dirty work. You just tell it what URL to
contact, specifying the necessary parameters, and it fetches the response for you.






June 7, 2010
AJAX