Introducing XMLHttpRequest

Ajax tutorial | PREV | NEXT

To make all this flash and wonder actually happen, you need to become intimately familiar with a JavaScript object called XMLHttpRequest. This little object -- which has actually been around in several browsers for quite a while -- is the key to Web 2.0, Ajax, and pretty much everything else you learn about in this column for the next several months. To give you a really quick overview, these are just a few of the methods and properties you'll use on this object:

Don't worry if you don't understand all of this (or any of this for that matter) -- you'll learn about each method and property in the next several articles. What you should get out of this, though, is a good idea of what to do with XMLHttpRequest. Notice that each of these methods and properties relate to sending a request and dealing with a response. In fact, if you saw every method and property of XMLHttpRequest, they would all relate to that very simple request/response model. So clearly, you won't learn about an amazing new GUI object or some sort of super-secret approach to creating user interaction; you will work with simple requests and simple responses. It might not sound exciting, but careful use of this one object can totally change your applications.

The simplicity of new

First, you need to create a new variable and assign it to an instance of the XMLHttpRequest object. That's pretty simple in JavaScript; you just use the new keyword with the object name, like you see in Listing 1.

Listing 1. Create a new XMLHttpRequest object
<script language="javascript" type="text/javascript">
var request = new XMLHttpRequest();
</script>
That's not too hard, is it? Remember, JavaScript doesn't require typing on its variable, so you don't need anything like you see in Listing 2 (which might be how you'd create this object in Java).
Listing 2. Java pseudo-code for creating XMLHttpRequest
XMLHttpRequest request = new XMLHttpRequest();

So you create a variable in JavaScript with var, give it a name (like "request"), and then assign it to a new instance of XMLHttpRequest. At that point, you're ready to use the object in your functions.

Error handling

In real life, things can go wrong and this code doesn't provide any error-handling. A slightly better approach is to create this object and have it gracefully fail if something goes wrong. For example, many older browsers (believe it or not, people are still using old versions of Netscape Navigator) don't support XMLHttpRequest and you need to let those users know that something has gone wrong. Listing 3 shows how you might create this object so if something fails, it throws out a JavaScript alert.
Listing 3. Create XMLHttpRequest with some error-handling abilities

<script language="javascript" type="text/javascript">
var request = false;
try {
  request = new XMLHttpRequest();
} catch (failed) {
  request = false;
}

if (!request)
  alert("Error initializing XMLHttpRequest!");
</script>

Make sure you understand each of these steps:

  1. Create a new variable called request and assign it a false value. You'll use false as a condition that means the XMLHttpRequest object hasn't been created yet.
  2. Add in a try/catch block:
    1. Try and create the XMLHttpRequest object.
    2. If that fails (catch (failed)), ensure that request is still set to false.
  3. Check and see if request is still false (if things are going okay, it won't be).
  4. If there was a problem (and request is false), use a JavaScript alert to tell users there was a problem.

This is pretty simple; it takes longer to read and write about than it does to actually understand for most JavaScript and Web developers. Now you've got an error-proof piece of code that creates an XMLHttpRequest object and even lets you know if something went wrong.

Dealing with Microsoft

This all looks pretty good ... at least until you try this code in Internet Explorer. If you do, you're going to get something that looks an awful lot like Figure 1.


Figure 1. Internet Explorer reporting an error
Internet Explorer reporting an error

Clearly, something isn't working; Internet Explorer is hardly an out-of-date browser and about 70 percent of the world uses Internet Explorer. In other words, you won't do well in the Web world if you don't support Microsoft and Internet Explorer! So, you need a different approach to deal with Microsoft's browsers.
Microsoft playing nice?
Much has been written about Ajax and Microsoft's increasing interest and presence in that space. In fact, Microsoft's newest version of Internet Explorer -- version 7.0, set to come out late in 2006 -- is supposed to move to supporting XMLHttpRequest directly, allowing you to use the new keyword instead of all the Msxml2.XMLHTTP creation code. Don't get too excited, though; you'll still need to support old browsers, so that cross-browser code isn't going away anytime soon.

It turns out that Microsoft supports Ajax, but calls its version of XMLHttpRequest something different. In fact, it calls it several different things. If you're using a newer version of Internet Explorer, you need to use an object called Msxml2.XMLHTTP; some older versions of Internet Explorer use Microsoft.XMLHTTP. You need to support these two object types (without losing the support you already have for non-Microsoft browsers). Check out Listing 4 which adds Microsoft support to the code you've already seen.

Listing 4. Add support for Microsoft browsers
<script language="javascript" type="text/javascript">
var request = false;
try {
  request = new XMLHttpRequest();
} catch (trymicrosoft) {
  try {
    request = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (othermicrosoft) {
    try {
      request = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (failed) {
      request = false;
    }
  }
}

if (!request)
  alert("Error initializing XMLHttpRequest!");
</script>

It's easy to get lost in the curly braces, so I'll walk you through this one step at a time:

  1. Create a new variable called request and assign it a false value. Use false as a condition that means the XMLHttpRequest object isn't created yet.
  2. Add in a try/catch block:
    1. Try and create the XMLHttpRequest object.
    2. If that fails (catch (trymicrosoft)):
      1. Try and create a Microsoft-compatible object using the newer versions of Microsoft (Msxml2.XMLHTTP).
      2. If that fails (catch (othermicrosoft)), try and create a Microsoft-compatible object using the older versions of Microsoft (Microsoft.XMLHTTP).
    3. If that fails (catch (failed)), ensure that request is still set to false.
  3. Check and see if request is still false (if things are okay, it won't be).
  4. If there was a problem (and request is false), use a JavaScript alert to tell users there was a problem.

Make these changes to your code and try things out in Internet Explorer again; you should see the form you created (without an error message). In my case, that results in something like Figure 2.
Figure 2. Internet Explorer working normally
Internet Explorer working normally

Static versus dynamic

Take a look back at Listings 1, 3, and 4 and notice that all of this code is nested directly within script tags. When JavaScript is coded like that and not put within a method or function body, it's called static JavaScript. This means that the code is run sometime before the page is displayed to the user. (It's not 100 percent clear from the specification precisely when this code runs and browsers do things differently; still, you're guaranteed that the code is run before users can interact with your page.) That's usually how most Ajax programmers create the XMLHttpRequest object.

That said, you certainly can put this code into a method as shown in Listing 5.


Listing 5. Move XMLHttpRequest creation code into a method
<script language="javascript" type="text/javascript">

var request;

function createRequest() {
  try {
    request = new XMLHttpRequest();
  } catch (trymicrosoft) {
    try {
      request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (othermicrosoft) {
      try {
        request = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (failed) {
        request = false;
      }
    }
  }

  if (!request)
    alert("Error initializing XMLHttpRequest!");
}
</script>

With code setup like this, you'll need to call this method before you do any Ajax work. So you might have something like Listing 6.


Listing 6. Use an XMLHttpRequest creation method
<script language="javascript" type="text/javascript">

var request;

function createRequest() {
  try {
    request = new XMLHttpRequest();
  } catch (trymicrosoft) {
    try {
      request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (othermicrosoft) {
      try {
        request = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (failed) {
        request = false;
      }
    }
  }

  if (!request)
    alert("Error initializing XMLHttpRequest!");
}

function getCustomerInfo() {
  createRequest();
  // Do something with the request variable
}
</script>

The only concern with this code -- and the reason most Ajax programmers don't use this approach -- is that it delays error notification. Suppose you have a complex form with 10 or 15 fields, selection boxes, and the like, and you fire off some Ajax code when the user enters text in field 14 (way down the form). At that point, getCustomerInfo() runs, tries to create an XMLHttpRequest object, and (for this example) fails. Then an alert is spit out to the user, telling them (in so many words) that they can't use this application. But the user has already spent time entering data in the form! That's pretty annoying and annoyance is not something that typically entices users back to your site.

In the case where you use static JavaScript, the user is going to get an error as soon as they hit your page. Is that also annoying? Perhaps; it could make users mad that your Web application won't run on their browser. However, it's certainly better than spitting out that same error after they've spent 10 minutes entering information. For that reason alone, I encourage you to set up your code statically and let users know early on about possible problems.