Live, From Your Server
The rise of AJAX is probably the biggest success story of the web. An acronym for "Asynchronous JavaScript and XML" (even though it was never restricted to the XML data format), AJAX is the process by which JavaScript can request more data from the server without refreshing the page. It's what makes modern web-based e-mail useful, loads the "infinite stream" of many social networks, and powers the autocomplete behavior on search engines. Thanks to AJAX, we can write web applications with fast, responsive user interfaces, while still leaving the heavy data-lifting to the server.
One of jQuery's biggest advantages in its early days was that it smoothed over the cross-browser differences in performing AJAX requests, which continue to be a pitfall with this particular browser feature. It also provides a shorter, simpler API for making these requests, since the built-in browser methods use long, frustrating names like XMLHttpRequest and a set of hard-to-remember numerical status codes.
Making our first AJAX request is simple. Open up your browser console on this page, and type the following code, which calls $.ajax with a configuration object as its only argument, specifying the URL:
$.ajax({url: "index.html"});
You should see two lines on the console in response. The first is the return value from $.ajax. The second is a log of the request itself, which will usually include the request method (usually "GET" or "POST"), URL, and time taken for the server to respond.
What you don't see on the console is the response to this request--in this case, the contents of index.html. Remember the first A in AJAX: asynchronous. When you make a request to the server via JavaScript, the browser fires off that request but then continues running your code. Remember, your browser runs JavaScript in lockstep with its user interface, and these requests could take up to several seconds to complete. If we paused JavaScript while the request went to the server and returned, we'd have to freeze the rest of the browser as well, which would be a terrible experience for users. So how do we keep running code, but handle the server's response when it finally comes in?
The answer lies in that request object that $.ajax returned. The request is a special kind of object called a promise (also known as a deferred or future, depending on the JavaScript library). A promise represents a one-time process, and allows you to attach functions that are called when that process either succeeds or fails. We can use the promise's done() method to attach a function, and jQuery will call it when the request finishes:
var request = $.ajax({
url: "index.html"
});
request.done(function(data) {
console.log("This will run second.");
//here's the response!
console.log(data);
});
request.fail(function() {
console.log("Called if the request was unsuccessful.")
});
console.log("This will run first.")
This pattern should look a little familiar: it's not that different from working with browser events and jQuery's on() method, including the fact that our callback functions will run out of order with the rest of our code. Promises actually provide a lot of interesting ways to keep asynchronicity from being too headache-inducing, but what we're mostly concerned with is done() and fail().
Request Customization
To make AJAX useful, we need to be able to customize our request more than just asking for a specific URL. We may want to add parameters to it, to ask for specific information, or send the contents of a form to its handler on the server without requiring a page refresh. To do so, we'll fill in the configuration object we pass as $.ajax's argument with a few new properties. The complete list of settings is available at the jQuery documentation page, but here are some of the more common settings.
data | An object or string containing parameters to be sent back to the server. jQuery will translate these into the URL parameters or request body, depending on the HTTP method used. |
cache | By default, the browser caches most requests. Set this to false to make sure you get a fresh copy each time. |
dataType | jQuery will try to figure out the type of data the server sends automatically, whether that's XML, JSON, or HTML. If it doesn't correctly guess, you can force it to use a specific type by setting this property. |
type | The HTTP method to use for the request. This is "GET" for most requests and "POST" when sending data to a form handler or web service. You can also use the other HTTP verbs, such as "PUT" or "DELETE" in most modern browsers, but these are more rare. |
Let's say that we wanted to submit a form to a server without requiring a page refresh. jQuery provides a helper function, named serialize(), to collect the form values for transmission, but we'll need to set a few extra parameters. The following code causes clicks on the form's submit button to send via AJAX instead.
//when you click the submit button...
$('form button, form input[type=submit]').on('click', function(e) {
//cancel the normal form behavior
e.preventDefault();
//gather up the form's values
var form = $(this).closest('form');
var formData = form.serialize();
//send the request
var request = $.ajax({
url: "formHandler.php",
data: formData,
type: "POST" //forms are always posted
});
//temporarily replace the form, to prevent double-submit
form.html("Please wait...");
//when the server replies...
request.done(function(response) {
//replace the form contents with the response
form.html(response);
});
//if something went wrong
request.fail(function() {
form.html("Sorry, something's gone wrong. Please try again later.")
});
});
The beauty of this particular approach is that we don't need to change anything on the server to make it work. As far as it is concerned, it got a form submission just like any other, and responded to it as normal. But our users did not have to wait for a full page refresh, or wonder if the information was going through. Their experience was instantly responsive, with helpful loading and error messages every step of the way.
JSON: Not Just for Friday the 13th
We've mentioned JSON once or twice now. It stands for JavaScript Object Notation, and it's a format for exchanging information on the web that will look pretty familiar to you. Here's a sample:
{
"author": {
"last": "Herbert",
"first": "Frank"
},
"books": ["Dune", "Children of Dune"],
"authorID": 927492,
"local": false
}
That's right: JSON is just JavaScript object literals, with some additional rules applied for strictness. Those rules are:
- All property names must be quoted using double-quotes.
- Only primitive values and collections are allowed: no functions, and no JavaScript expressions
- All strings must be quoted in double-quotes.
JSON has become extremely popular even outside of JavaScript as a format for storing and transferring data. Compared to other formats, like XML, it's compact and has relatively little "noise" around its values. When we communicate over AJAX, it's common to use JSON as a way of expressing the parameters of our request and its results. If a server replies as JSON, jQuery will automatically translate the response into a JavaScript object before passing it to your request's callback function. You can also perform this translation manually using the JSON object in your browser:
var data = {
"hello": "World"
}
//This converts from data to JSON text.
//Please forgive the incredibly stupid "stringify" name
var jsonString = JSON.stringify(data);
//We can change it back with JSON.parse()
var decoded = JSON.parse(jsonString);
Example Code
Let's build a basic AJAX-powered autocomplete. For the purposes of the code below, assume that the service at http://youcompleteme.com will return a JSON array of suggestions when sent a request with the current input contents.
Practice Questions
- In the following code, the value of remote logged out to the console will be undefined, and not the value sent by the server. Why? How would we fix that?
var remote; var request = $.ajax({ url: "/server/url.php" }); request.done(function(data) { remote = data; }); console.log(remote);
- One use for AJAX requests on many web pages is to create an "infinite scroll" page, such as that used by many social networks. At a high level, describe how you would implement such a page (hint: you may want to look at the window's scroll event).
- If you have used a language other than JavaScript on the server, find out how to turn a data structure into JSON in your language of choice. Write a simple page that returns a weather prediction as JSON, then use AJAX and JavaScript to insert that prediction into the page.