Sending requests with XMLHttpRequest |
Once you have your request object, you can begin the request/response cycle. Remember, XMLHttpRequest's only purpose is to allow you to make requests and receive responses. Everything else -- changing the user interface, swapping out images, even interpreting the data that the server sends back -- is the job of JavaScript, CSS, or other code in your pages. With XMLHttpRequest
ready for use, now you can make a request to a server.
Ajax has a sandbox security model. As a result, your Ajax code (and specifically, the XMLHttpRequest object) can only make requests to the same domain on which it's running. You'll learn lots more about security and Ajax in an upcoming article, but for now realize that code running on your local machine can only make requests to server-side scripts on your local machine. If you have Ajax code running on www.breakneckpizza.com, it must make requests to scripts that run on www.breakneckpizza.com.
The first thing you need to determine is the URL of the server to connect to. This isn't specific to Ajax -- obviously you should know how to construct a URL by now -- but is still essential to making a connection. In most applications, you'll construct this URL from some set of static data combined with data from the form your users work with. For example, Listing 7 shows some JavaScript that grabs the value of the phone number field and then constructs a URL using that data.
<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!");
function getCustomerInfo() {
var phone = document.getElementById("phone").value;
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
}
</script>
Nothing here should trip you up. First, the code creates a new variable named phone
and assigns the value of the form field with an ID of "phone." Listing 8 shows the XHTML for this particular form in which you can see the phone
field and its id
attribute.
<body>
<p><img src="breakneck-logo_4c.gif" alt="Break Neck Pizza" /></p>
<form action="POST">
<p>Enter your phone number:
<input type="text" size="14" name="phone" id="phone"
onChange="getCustomerInfo();" />
</p>
<p>Your order will be delivered to:</p>
<div id="address"></div>
<p>Type your order in here:</p>
<p><textarea name="order" rows="6" cols="50" id="order"></textarea></p>
<p><input type="submit" value="Order Pizza" id="submit" /></p>
</form>
</body>
Also notice that when users enter their phone number or change the number, it fires off the getCustomerInfo()
method shown in Listing 8. That method then grabs the number and uses it to construct a URL string stored in the url
variable. Remember: Since Ajax code is sandboxed and can only connect to the same domain, you really shouldn't need a domain name in your URL. In this example, the script name is /cgi-local/lookupCustomer.php
. Finally, the phone number is appended to this script as a GET parameter: "phone=" + escape(phone)
.
If you've never seen the escape()
method before, it's used to escape any characters that can't be sent as clear text correctly. For example, any spaces in the phone number are converted to %20
characters, making it possible to pass the characters along in the URL.
You can add as many parameters as you need. For example, if you wanted to add another parameter, just append it onto the URL and separate parameters with the ampersand (&
) character [the first parameter is separated from the script name with a question mark (?
)].
With a URL to connect to, you can configure the request. You'll accomplish this using the open()
method on your XMLHttpRequest object. This method takes as many as five parameters:
GET
or POST
, but you can also send HEAD
requests. Does open() open?
Internet developers disagree about what exactly the open()
method does. What it does not do is actually open a request. If you were to monitor the network and data transfer between your XHTML/Ajax page and the script that it connects to, you wouldn't see any traffic when the open()
method is called. It's unclear why the name was chosen, but it clearly wasn't a great choice.
Typically, you'll use the first three of these. In fact, even when you want an asynchronous request, you should specify "true" as the third parameter. That's the default setting, but it's a nice bit of self-documentation to always indicate if the request is asynchronous or not.
Put it all together and you usually end up with a line that looks a lot like Listing 9.
Listing 9. Open the request
function getCustomerInfo() {
var phone = document.getElementById("phone").value;
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
}
Once you have the URL figured out, then this is pretty trivial. For most requests, using GET
is sufficient (you'll see the situations in which you might want to use POST
in future articles); that, along with the URL, is all you need to use open()
.
In a later article in this series, I'll spend significant time on writing and using asynchronous code, but you should get an idea of why that last parameter in open()
is so important. In a normal request/response model -- think Web 1.0 here -- the client (your browser or the code running on your local machine) makes a request to the server. That request is synchronous; in other words, the client waits for a response from the server. While the client is waiting, you usually get at least one of several forms of notification that you're waiting:
This is what makes Web applications in particular feel clunky or slow -- the lack of real interactivity. When you push a button, your application essentially becomes unusable until the request you just triggered is responded to. If you've made a request that requires extensive server processing, that wait might be significant (at least for today's multi-processor, DSL, no-waiting world).
An asynchronous request though, does not wait for the server to respond. You send a request and then your application continues on. Users can still enter data in a Web form, click other buttons, even leave the form. There's no spinning beachball or whirling hourglass and no big application freeze. The server quietly responds to the request and when it's finished, it let's the original requestor know that it's done (in ways you'll see in just a moment). The end result is an application that doesn't feel clunky or slow, but instead is responsive, interactive, and feels faster. This is just one component of Web 2.0, but it's a very important one. All the slick GUI components and Web design paradigms can't overcome a slow, synchronous request/response model.
Once you configure the request with open()
, you're ready to send the request. Fortunately, the method for sending a request is named more properly than open()
; it's simply called send()
.
send()
takes only a single parameter, the content to send. But before you think too much on that, recall that you are already sending data through the URL itself:
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
Although you can send data using send()
, you can also send data through the URL itself. In fact, in GET
requests (which will constitute as much as 80 percent of your typical Ajax usage), it's much easier to send data in the URL. When you start to send secure information or XML, then you want to look at sending content through send()
(I'll discuss both secure data and XML messaging in a later article in this series). When you don't need to pass data along through send()
, then just pass null
as the argument to this method. So, to send a request in the example you've seen throughout this article, that's exactly what is needed (see Listing 10).
function getCustomerInfo() {
var phone = document.getElementById("phone").value;
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
request.send(null);
}
At this point, you've done very little that feels new, revolutionary, or asynchronous. Granted, that little keyword "true" in the open()
method sets up an asynchronous request. But other than that, this code resembles programming with Java servlets and JSPs, PHP, or Perl. So what's the big secret to Ajax and Web 2.0? The secret revolves around a simple property of XMLHttpRequest called onreadystatechange
.
First, be sure you understand the process that you created in this code (review Listing 10 if you need to). A request is set up and then made. Additionally, because this is a synchronous request, the JavaScript method (getCustomerInfo()
in the example) will not wait for the server. So the code will continue; in this case, that means that the method will exit and control will return to the form. Users can keep entering information and the application isn't going to wait on the server.
This creates an interesting question, though: What happens when the server has finished processing the request? The answer, at least as the code stands right now, is nothing! Obviously, that's not good, so the server needs to have some type of instruction on what to do when it's finished processing the request sent to it by XMLHttpRequest
.
This is where that onreadystatechange
property comes into play. This property allows you to specify a callback method. A callback allows the server to (can you guess?) call back into your Web page's code. It gives a degree of control to the server, as well; when the server finishes a request, it looks in the XMLHttpRequest object and specifically at the onreadystatechange
property. Whatever method is specified by that property is then invoked. It's a callback because the server initiates calling back into the Web page -- regardless of what is going in the Web page itself. For example, it might call this method while the user is sitting in her chair, not touching the keyboard; however, it might also call the method while the user is typing, moving the mouse, scrolling, clicking a button ... it doesn't matter what the user is doing.
Referencing a function in JavaScript
JavaScript is a loosely typed language and you can reference just about anything as a variable. So if you declare a function called updatePage()
, JavaScript also treats that function name as a variable. In other words, you can reference the function in your code as a variable named updatePage
.
This is actually where the asynchronicity comes into play: The user operates the form on one level while on another level, the server answers a request and then fires off the callback method indicated by the onreadystatechange
property. So you need to specify that method in your code as shown in Listing 11.
function getCustomerInfo() {
var phone = document.getElementById("phone").value;
var url = "/cgi-local/lookupCustomer.php?phone=" + escape(phone);
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);
}
Pay close attention to where in the code this property is set -- it's before send()
is called. You must set this property before the request is sent, so the server can look up the property when it finishes answering a request. All that's left now is to code the updatePage()
which is the focus of the last section in this article.
Home | Ajax tutorials | JavaScript Editor | Get Advanced JavaScript and Ajax Editor, Validator and Debugger! 1st JavaScript Editor. |