Ajax
When you want a user to send data to your server — once they have filled out a form, for example — they normally have to submit the form and then wait as the entire page is refreshed. Similarly, if you want to retrieve new data from the server, you have no choice but to load a whole new page.
This is inefficient, time-consuming, and particularly frustrating if there’s only a small amount of data being sent back and forth. In this tutorial, you’ll be introduced to Ajax, a technology that allows you to send these requests through small JavaScript calls, meaning the user doesn’t have to wait for the page to refresh.
This page was last updated on 2012-08-21
What is “Ajax”?
Ajax is actually a family of technologies that have been available for years. The means to make requests to the server using only JavaScript were built into Internet Explorer 5.5, but the possibilities of the technology were overlooked. It was only in 2005 that the techniques were rediscovered and used, notably to excellent effect in Google’s » GMail web application.
The term Ajax, which stands for “Asynchronous JavaScript and XML”, was first coined by Jesse James Garrett in his somewhat infamous article, » Ajax: A New Approach to Web Applications.
So let’s take each of those parts in isolation. Ajax is:
- Asynchronous
- This means that when you send a request, you wait for the response to come back, but are free to do other things while you wait. The response probably won’t come back immediately, so you set up a function that will wait for the response to be sent back by the server, and react to it once that happens.
- JavaScript
- JavaScript is used to make a request to the server. Once the response is returned by the server, you will generally use some more JavaScript to modify the current page’s document object model in some way to show the user that the submission went through successfully.
- XML
- The data that you receive back from the server will often be packaged up as a snippet of XML, so that it can be easily processed with JavaScript. This data can be anything you want, and as long as you want.
There’s nothing really new about what is happening here. We’re requesting a file (which will often be a server-side script, coded in something like PHP), and receiving a page as the response. This is how the web works already — the only difference is that now we can make these requests from JavaScript.
Cross-browser Ajax
Unfortunately Ajax is supported slightly differently in IE than it is Safari, Opera and Mozilla-based browsers like Firefox. This leaves us with two possible routes: using code branching to send the right code to each browser based on which model they support, or using a JavaScript library that wraps up the Ajax code into a single object, and means you don’t have to worry about browser incompatibilities.
We’re going for the latter option, and will be using a JavaScript library. There are dozens of them in existence, each with their own boons and vices. Popular examples include prototype, Dojo, and the Yahoo UI library. For the duration of this tutorial, we’re going to be using a very useful library called » Sarissa. Sarissa contains methods that will create the request for us, and also methods that help with processing the XML that we receive back in the response. This means we don’t have to mess with the intricacies of Ajax, and allows our code to be quite elegant.
Building a Request
So, first » download the Sarissa JavaScript source code file (called “sarissa.js”) and then upload it with the rest of your files. You’ll need to show your pages where the library is, so add this line to the top of any pages that need access to Ajax:
<script type="text/javascript" src="sarissa.js"></script>
First of all, the project we’re going to work on throughout this tutorial is to make form submissions for a survey less painful. You can get a glimpse of what we’re aiming for in this example page. The user will be presented with a set of options, be asked to choose one, and press submit. Instead of having to reload the whole page to submit the form, which might turn some users off participating in the survey, we will instead submit the form with Ajax, and update the page when the request succeeds.
I’ll go through the four steps required to get this working, and we’ll get onto the full code later. First we’ll begin to construct our request. The specific method we use to do this is called “XML HTTP Request.” Through Sarissa, we create a cross-browser XML HTTP Request object:
var xmlhttp = new XMLHttpRequest();
That code there will take care of the browser compatibility issues, and leave you with an object that will work in whatever the user’s browser can support. Next we specify the page that we’re requesting:
xmlhttp.open('POST', 'rating-submit.php', true);
The first argument to this function can be set to either 'GET'
or 'POST'
. In this instance, because we’re sending some data to the server, we use the ‘POST’ method. If we were only pulling additional data from the server, we could use the ‘GET’ method safely. This distinction is important to get right. Only use ‘GET’ if you are not changing anything on the server, just retrieving some data. Otherwise you should always use ‘POST’. Keep the names capitalised.
Obviously you will need to change that URL to the filename of the script you’re using on your own server. The third argument controls whether the request is asynchronous or synchronous. If set to false
, the call is made synchronous and the user’s browser will actually lock up until the response is received, which is not what we want. You will almost always leave this as true
.
The next step is to set up the function that will wait to be called until a response is returned by the server. This function is responsible for doing something to show the user that the submission has succeeded. Usually, adding a small message to the page is enough. The “callback function,” as it is called, always follows the same structure, which looks like this:
xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { // Your callback code goes here } }
As a request is made, it passes through various states. We check the object’s readyState
property here to see if it has made it to stage 4, which means that the response is complete.
The last step now that this is all set up is to actually send the request:
xmlhttp.send(null);
This will send the request and then return immediately. It then waits for the response to enter readyState
4. When that happens, your callback function is called, and whatever data was sent back in the response (if any) is available in the xmlhttp.responseXML
variable. And that’s all there is to it.
Building the Script
So now that we have a skeleton for the script, we can start filling it out properly. This script will use a number of functions from the very useful util-functions.js file, which is a collection of functions I put together that you are welcome to download and use in your own projects.
First, we’re going to loop through the page once it loads and add an event handler to any form with the class
“ajaxify.” The event handler will be fired when the form is submitted:
addEvent(window, 'load', init, false); function init() { if (!Sarissa || !document.getElementsByTagName) return; var formElements = document.getElementsByTagName('form'); for (var i = 0; i < formElements.length; i++) { if (formElements[i].className.match(/\bajaxify\b/)) { addEvent(formElements[i], 'submit', submitRating, false); } } }
So here we’re first checking if the user’s browser has correctly loaded the Sarissa object, and is also able to do the document.getElementsByTagName
method. If this doesn’t work out, we return
early. Then we’re looping through all the forms on the page and adding an event handler to any that have a class name that matches the string “ajaxify.” Next we have to actually write that submitRating
function. It looks like this:
function submitRating(e) { /* Cancel the submit event, and find out which form was submitted */ knackerEvent(e); var target = window.event ? window.event.srcElement : e ? e.target : null; if (!target) return; /* Set up the request */ var xmlhttp = new XMLHttpRequest(); xmlhttp.open('POST', 'rating-submit.php', true); /* The callback function */ xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { if (xmlhttp.status == 200) addRatingFeedback(xmlhttp.responseXML, target); else target.submit(); } } /* Send the POST request */ xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlhttp.send('rating=' + target.elements['rating'].value); … }
The Callback Function
Let’s look at the callback function in a little more depth. We’ve added a new check in there.
if (xmlhttp.readyState == 4) { if (xmlhttp.status == 200) addRatingFeedback(xmlhttp.responseXML, target); else target.submit(); }
Just because we’ve received a response back doesn’t mean that everything went according to plan. When the response is sent back by the server, it is always sent with a status code, of which there are many. The response code 200 (known as “Ok”) means that the response went through without a hitch, which is obviously what we want to hear. If xmlhttp.status
is set to 200, then we can go ahead and add some feedback to the page.
Otherwise, in the case of a timeout or if the script returned a 404 error, we need to have a backup plan. Here, I’ve decided to simply submit the form normally. This illustrates an important point: even with all of this Ajax goodness, you still need to have a script on the server that will deal with normal form submits from users with browsers that don’t support Ajax, or just for those times when something goes wrong.
Sending the POST Request
Sending a POST request, as opposed to a GET request, requires an extra step. We need to set a special attribute of the request, so that it accepts some data from the form. We then need to extract the relevant data from the form and include this in the send()
call.
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlhttp.send('rating=' + target.elements['rating'].value);
As you can see, we’re no longer simply calling send(null)
. We send the data from the form in the format “name=value&name=value...”. So here we’re working with the select
called “rating”, and sending its value, which will end up looking something like “rating=3”.
The Server-side Script
Everyone’s server-side script is going to be different, but for the sake of completeness, here’s what the one in our example looks like:
<?php header('Content-type: text/xml'); $rating = $_POST['rating']; function record_rating($rating) { // Add data to database here return 1; } ?> <xmlresponse> <rating><?= $rating ?></rating> <result><?= record_rating($rating) ?></result> </xmlresponse>
This simply sends back a small XML document. You can make up whatever tags you want. The “record_rating” method I’ve glossed over here will save some data on the server, and then return a 1 if the operation was successful, but a 0 if the operation failed. This way you can check the contents of the <result>
tag and add feedback appropriately.
Adding Feedback
The final step is to check the response and add feedback to the page appropriately. Again, this will be different for everyone’s implementation. The XML that was sent back by your server-side script is available in the xmlhttp.responseXML
property. You can treat this just as you would a HTML document, which means that methods calls like the one below will yield the contents of certain elements in the XML:
xmlhttp.responseXML.getElementsByTagName('result')[0].firstChild.data;
That code snippet above will return the contents of the first <result>
element in the response (i.e. the value you should check to make sure the server-side script executed correctly). The feedback you give the user can range from popping up an alert()
to rearranging the page using DOM calls. In the example page you can see that I add new text to the page, restyle the form and then disable the form inputs so that the user doesn’t submit the same form twice.
So there you have it, an Ajax-ified page from start to finish. Ajax has lots of useful applications. Have fun with it.