To subscribe, click here.

Learn about
RSS subscriptions.



Advanced Search
Build Your Own AJAX Web Applications Part 2/3
By SitePoint Books | Published  5/Sep/2006 | Tutorials | Unrated
Page 3

This method changes the onreadystate event handler to an empty function, calls the abort method on your instance of the XMLHttpRequest class, then destroys the instance you've created. That way, any properties that have been set exclusively for the request that's being aborted are reset. Next time a request is made, the init method will be called and those properties will be reinitialized.

So, why do we need to change the onreadystate event handler? Many implementations of XMLHttpRequest will fire the onreadystate event once abort is called, to indicate that the request's state has been changed. What's worse is that those events come complete with a readyState of 4, which indicates that everything completed as expected (which is partly true, if you think about it: as soon as we call abort, everything should come to a stop and our instance of XMLHttpRequest should be ready to send another request, should we so desire). Obviously, we don't want our response handler to be invoked when we abort a request, so we remove the existing handler just before we call abort.

Wrapping it Up

Given the code we have so far, the Ajax class needs just two things in order to make a request:

  • a target URL
  • a handler function for the response

Let's provide a method called doGet to set both of these properties, and kick off the request:

Example 2.15. ajax.js (excerpt)

this.doGet = function(url, hand, format) {
 this.url = url;
 this.handleResp = hand;
 this.responseFormat = format || 'text';
 this.doReq();
};

You'll notice that, along with the two expected parameters, url and hand, the function has a third parameter: format. This is an optional parameter that allows us to change the format of the server response that's passed to the handler function.

If we don't pass in a value for format, the responseFormat property of the Ajax class will default to a value of text, which means your handler will be passed the value of the responseText property. You could, instead, pass xml or object as the format, which would change the parameter that's being passed to the response handler to an XML DOM or XMLHttpRequest object.

Example: a Simple Test Page

It's finally time to put everything we've learned together! Let's create an instance of this Ajax class, and use it to send a request and handle a response.

Now that our class's code is in a file called ajax.js, any web pages in which we want to use our Ajax class will need to include the Ajax code with a
   
 
 
 

This script gives us a shiny, new instance of the Ajax class. Now, let's make it do something useful.

To make the most basic request with our Ajax class, we could do something like this:

Example 2.17. ajaxtest.html (excerpt)

This creates an instance of our Ajax class that will make a simple GET request to a page called fakeserver.php, and pass the result back as text to the hand function. If fakeserver.php returned an XML document that you wanted to use, you could do so like this:

Example 2.18. ajaxtest.html (excerpt)

You would want to make absolutely sure in this case that somepage.php was really serving valid XML and that its Content-Type HTTP response header was set to text/xml (or something else that was appropriate).

Creating the Page

Now that we have created the Ajax object, and set up a simple handler function for the request, it's time to put our code into action.

The Fake Server Page

In the code above, you can see that the target URL for the request is set to a page called fakeserver.php. To use this demonstration code, you'll need to serve both ajaxtest.html and fakeserver.php from the same PHP-enabled web server. You can do this from an IIS web server with some simple ASP, too. The fake server page is a super-simple page that simulates the varying response time of a web server using the PHP code below:

Example 2.19. fakeserver.php

header('Content-Type: text/plain');
sleep(rand(3, 12));
print 'ok';
?>

That's all this little scrap of code does: it waits somewhere between three and 12 seconds, then prints ok.

The fakeserver.php code sets the Content-Type header of the response to text/plain. Depending on the content of the page you pass back, you might choose another Content-Type for your response. For example, if you're passing an XML document back to the caller, you would naturally want to use text/xml.

This works just as well in ASP, although some features (such as sleep) are not as easily available, as the code below illustrates:

Example 2.20. fakeserver.asp

<%
Response.ContentType = "text/plain"
' There is no equivalent to sleep in ASP.
Response.Write "ok"
%>

Throughout this book, all of our server-side examples will be written in PHP, although they could just as easily be written in ASP, ASP.NET [33], Java, Perl, or just about any language that can serve content through a web server.

Use the setMimeType Method

Imagine that you have a response that you know contains a valid XML document that you want to parse as XML, but the server insists on serving it to you as text/plain. You can force that response to be parsed as XML in Firefox and Safari by adding an extra call to setMimeType, like so:

var ajax = new Ajax();
ajax.setMimeType('text/xml');
ajax.doGet('/fakeserver.php', hand, 'xml');

Naturally, you should use this approach only when you're certain that the response from the server will be valid XML, and you can be sure that the browser is Firefox or Safari.

Hitting the Page

Now comes the moment of truth! Hit your local web server, load up ajaxtest.html, and see what you get. If everything is working properly, there will be a few moments' delay, and then you'll see a standard JavaScript alert like the one in Figure 2.2 that says simply ok.

1542_fig2.2
Figure 2.2. Confirmation that your Ajax class is working as expected

Now that all is well and our Ajax class is functioning properly, it's time to move to the next step.

Example: a Simple AJAX App

Okay, so using the awesome power of AJAX to spawn a tiny little JavaScript alert box that reads "ok" is probably not exactly what you had in mind when you bought this book. Let's implement some changes to our example code that will make this XMLHttpRequest stuff a little more useful. At the same time, we'll create that simple monitoring application I mentioned at the start of this chapter. The app will ping a web site and report the time it takes to get a response back.

Laying the Foundations

We'll start off with a simple HTML document that links to two JavaScript files: ajax.js, which contains our library, and appmonitor1.js, which will contain the code for our application.

Example 2.21. appmonitor1.html

   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

 
           content="text/html; charset=iso-8859-1" />
   App Monitor
   
   
 
 
   


 

You'll notice that there's virtually no content in the body of the page -- there's just a single div element. This is fairly typical of web apps that rely on AJAX functions. Often, much of the content of AJAX apps is created by JavaScript dynamically, so we usually see a lot less markup in the body of the page source than we would in a non-AJAX web application for which all the content was generated by the server. However, where AJAX is not an absolutely essential part of the application, a plain HTML version of the application should be provided.

We'll begin our appmonitor1.js file with some simple content that makes use of our Ajax class:

Example 2.22. appmonitor1.js (excerpt)

var start = 0;
var ajax = new Ajax();

var doPoll = function() {
 start = new Date();
 start = start.getTime();
 ajax.doGet('/fakeserver.php?start=' + start, showPoll);
}

window.onload = doPoll;

We'll use the start variable to record the time at which each request starts -- this figure will be used to calculate how long each request takes. We make start a global variable so that we don't have to gum up the works of our Ajax class with extra code for timing requests -- we can set the value of start immediately before and after our calls to the Ajax object.

The ajax variable simply holds an instance of our Ajax class.

The doPoll function actually makes the HTTP requests using the Ajax class. You should recognize the call to the doGet method from our original test page.

Notice that we've added to the target URL a query string that has the start value as a parameter. We're not actually going to use this value on the server; we're just using it as a random value to deal with Internet Explorer's overzealous caching [34]. IE caches all GET requests made with XMLHttpRequest, and one way of disabling that "feature" is to append a random value into a query string. The milliseconds value in start can double as that random value. An alternative to this approach is to use the setRequestHeader method of the XMLHttpRequest class to set the If-Modified-Since header on the request.

Finally, we kick everything off by attaching doPoll to the window.onload event.

Handling the Result with showPoll

The second parameter we pass to doGet tells the Ajax class to pass responses to the function showPoll. Here's the code for that function:

Example 2.23. appmonitor1.js (excerpt)

var showPoll = function(str) {
 var pollResult = '';
 var diff = 0;
 var end = new Date();
 if (str == 'ok') {
   end = end.getTime();
   diff = (end - start) / 1000;
   pollResult = 'Server response time: ' + diff + ' seconds';
 }
 else {
   pollResult = 'Request failed.';
 }
 printResult(pollResult);
 var pollHand = setTimeout(doPoll, 15000);
}

This is all pretty simple: the function expects a single parameter, which should be the string ok returned from fakeserver.php if everything goes as expected. If the response is correct, the code does the quick calculations needed to figure out how long the response took, and creates a message that contains the result. It passes that message to pollResult for display.

In this very simple implementation, anything other than the expected response results in a fairly terse and unhelpful message: Request failed. We'll make our handling of error conditions more robust when we upgrade this app in the next chapter.

Once pollResult is set, it's passed to the printResult function:

Example 2.24. appmonitor1.js (excerpt)

function printResult(str) {
 var pollDiv = document.getElementById('pollDiv');
 if (pollDiv.firstChild) {
   pollDiv.removeChild(pollDiv.firstChild);
 }
 pollDiv.appendChild(document.createTextNode(str));
}

The printResult function displays the message that was sent from showPoll inside the lone div in the page.

Note the test in the code above, which is used to see whether our div has any child nodes. This checks for the existence of any text nodes, which could include text that we added to this div in previous iterations, or the text that was contained inside the div in the page markup, and then removes them. If you don't remove existing text nodes, the code will simply append the new result to the page as a new text node: you'll display a long string of text to which more text is continually being appended.

Why Not Use innerHTML?

You could simply update the innerHTML property of the div, like so:

document.getElementById('pollDiv').innerHTML = str;

The innerHTML property is not a web standard, but all the major browsers support it. And, as you can see from the fact that it's a single line of code (as compared with the four lines needed for DOM methods), sometimes it's just easier to use than the DOM methods. Neither way of displaying content on your page is inherently better.

In some cases, you may end up choosing a method based on the differences in rendering speeds of these two approaches (innerHTML can be faster than DOM methods). In other cases, you may base your decision on the clarity of the code, or even on personal taste.

Article Series
This article is part 2 of a 3 part series. Other articles in this series are shown below:
  1. Build Your Own AJAX Web Applications Part 1/3
  2. Build Your Own AJAX Web Applications Part 2/3
  3. Build Your Own AJAX Web Applications Part 3/3
Comments