Ajax isn't a technology, it's more of a pattern -- a way to identify and describe a useful design technique. Ajax is new in the sense that many developers are just beginning to be aware of it, but all of the components that implement an Ajax application have existed for several years. The current buzz is because of the emergence in 2004 and 2005 of some great dynamic Web UIs based on Ajax technology, most notably Google's GMail and Maps applications and the photo-sharing site Flickr. These UIs were sufficiently groundbreaking to be dubbed "Web 2.0" by some developers, with the resulting interest in Ajax applications skyrocketing.
A better shopping cart
You can use Ajax to enhance traditional Web applications, streamlining interaction by eliminating page loads. To demonstrate this, I'll use the simple example of a shopping cart that is dynamically updated as items are added to it. Incorporated into an online store, this approach would let users continue browsing and adding items to their carts without having to wait after each click for a full-page update. While some of the code in this article is specific to the shopping cart example, the techniques illustrated can be applied to any Ajax application. Listing 1 shows the relevant HTML code the shopping-cart example uses. I'll refer back to this HTML throughout the article.
The Ajax roundtrip
XMLHttpRequest. As the name suggests, it allows a
client-side script to perform HTTP requests, and it will parse an
XML server response. The first step in this Ajax roundtrip is to
XMLHttpRequest instance. The HTTP method to
use for the request (
POST) and the
destination URL are then set on the
Now, remember how that first a in Ajax stands for
asynchronous? When you send that HTTP request, you don't want
the browser to hang around waiting for the server to respond.
Instead, you want it to continue reacting to the user's interaction
with the page and deal with the server's response when it eventually
arrives. To accomplish this, you can register a callback function
XMLHttpRequest and then dispatch the
XMLHttpRequest asynchronously. Control then returns to
the browser, but the callback function will be called when the
server's response arrives.
On the Java Web server, the request arrives just like any other
HttpServletRequest. After parsing the request
parameters, the servlet invokes the necessary application logic,
serializes its response into XML, and writes it to the
Back on the client side, the callback function registered on the
XMLHttpRequest is now invoked to process the XML
document returned by the server. Finally, the user interface is
manipulate the page's HTML DOM. Figure 1 is a sequence diagram of
the Ajax roundtrip.
Now that you have a high-level view of the Ajax roundtrip, I'll zoom in for a more detailed look at each step along the way. Refer back to Figure 1 if you lose your place -- the sequence isn't entirely straightforward because of the asynchronous nature of the Ajax approach.
Dispatching an XMLHttpRequest
I'll start at the beginning of the Ajax sequence: creating and
XMLHttpRequest from the browser.
Unfortunately, the method to create an
2 smoothes out these browser-dependent wrinkles, detecting the
correct approach for the current browser and returning an
XMLHttpRequest ready to use. It's best to think of this
use it when you need an
Later, I'll discuss techniques to handle browsers that don't
XMLHttpRequest. For now, the examples assume
newXMLHttpRequest function from Listing 2 will
always return an
Getting back to the example shopping-cart scenario, I want to
invoke an Ajax interaction whenever the user hits the Add to Cart
button for a catalog item. The
onclick handler function
addToCart() is responsible for updating the state
of the cart through an Ajax call (see Listing
1). As shown in Listing 3, the first thing that
addToCart() needs to do is obtain an instance of
XMLHttpRequest by calling the
newXMLHttpRequest() function from Listing 2. Next, it
registers a callback function to receive the server's response (I'll
explain this in detail later; see Listing
Because the request will modify state on the server, I'll use an
POST to do the deed. Sending data through
POST requires three steps. First, I need to open a
POST connection to the server resource I'm
communicating with -- in this case a servlet mapped to the URL
cart.do. Next, I set a header on the
XMLHttpRequest stating that the content of the request
is form-encoded data. Finally, I send the request with form-encoded
data as the body.
Listing 3 puts these steps together.
And with that, you've seen the first part of setting up the Ajax roundtrip -- namely creating and dispatching the HTTP request from the client. Next up is the Java servlet code used to handle the request.
Servlet request handling
XMLHttpRequest with a servlet is largely
the same as handling a regular HTTP request from a browser. The
form-encoded data sent in the POST request's body can be obtained
HttpServletRequest.getParameter() calls. Ajax
requests take part in the same
HttpSession as regular
Web requests from the application. This is useful for the example
shopping-cart scenario because it lets me encapsulate the user's
shopping-cart state in a JavaBean and persist that state to the
session between requests.
Listing 4 is part of a simple servlet that handles Ajax requests
to update the shopping cart. A
Cart bean is retrieved
from the user's session and its state is updated according to the
request parameters. The
Cart is then serialized to XML,
and that XML is written to the
important to set the response's content type to
application/xml, otherwise the
XMLHttpRequest will not parse the response content into
an XML DOM.
Listing 5 shows an example of the XML produced by the
Cart.toXml() method. It's pretty straightforward. Note
generated attribute on the
element, which is a timestamp produced by
If you take a look at Cart.java in the application source code available from the Download section, you'll see that the XML is produced simply by appending strings together. While sufficient for this example, this is pretty much the worst way to produce XML from Java code. I'll suggest some better approaches in the next installment of this series.
So now you know how the
CartServlet responds to an
XMLHttpRequest. The next thing is to return to the
client side, where you can see how the XML response is used to
update page state.
readyState property of
XMLHttpRequest is a numeric value that gives the status
of the request's lifecycle. It changes from 0 for "uninitialized"
through to 4 for "complete." Each time the
readystatechange event fires and the
handler function attached via the
property is called.
3, you saw how the function
was called to create a handler function. This handler function was
then assigned to the
getReadyStateHandler() exploits the fact that functions
be parameters to other functions and can also create and return
other functions. It is the job of
getReadyStateHandler() to return a function that checks
XMLHttpRequest has completed and passes the
XML response onto the handler function specified by the caller.
Listing 6 is the code for
getReadyStateHandler() is a relatively complex piece
library, you can simply handle Ajax server responses without having
to deal with the internals of
important thing is that you understand how to use
getReadyStateHandler() in your own code.
3, you saw
getReadyStateHandler() called as
handlerFunction = getReadyStateHandler(req,
updateCart). The function returned by
getReadyStateHandler() in this case will check if the
XMLHttpRequest in the variable
completed and then call a function named
with the response XML.
Extracting the cart data
Listing 7 is the code of
updateCart() itself. The
function interrogates the shopping cart XML document using DOM calls
and updates the Web page (see Listing
1) to reflect the new cart contents. Focus here on the calls
used to extract data from the XML DOM. The
attribute on the
cart element, a timestamp created when
Cart was serialized to XML, is checked to ensure
that newer cart data is not overwritten by older cart data. Ajax
requests are inherently asynchronous, so this check safeguards
against server responses that arrive out of sequence.
And with that, the whistle-stop tour of the Ajax roundtrip is complete, although you may want to get the Web app running and see it in action (see the Download
Back to top
Challenges of using Ajax
As with any technology, there are plenty of ways to make mistakes with Ajax. Some of the problems I discuss here currently lack easy solutions but will improve as Ajax matures. As the developer community gains experience developing Ajax applications, best practices and guidelines will be documented.
Availability of XMLHttpRequest
One of the biggest issues facing Ajax developers is how to respond when
XMLHttpRequestisn't available. While the majority of modern browsers support
XMLHttpRequest, there will always be a minority of users whose browsers do not, or whose browser security settings prevent
XMLHttpRequestfrom being used. If you're developing a Web app to be deployed on a corporate intranet, you probably have the luxury of specifying which browsers are supported and assuming
XMLHttpRequestis always available. If you're deploying on the public Web, however, you must be aware that by presuming
XMLHttpRequestis available, you are potentially preventing users of older browsers, browsers for people with disabilities, or lightweight browsers on handheld devices from using your application.
Therefore, you should endeavor to make your application "degrade gracefully" and remain functional in browsers without
XMLHttpRequestwas available. Another approach would be to detect
XMLHttpRequestwhen a user logged in, and then serve up either an Ajax version of the application or a regular forms-based version as appropriate.
Some of the usability issues surrounding Ajax applications are more general. For instance, it can be important to let users know that their input has been registered, because the usual feedback mechanisms of the hourglass cursor and spinning browser "throbber" do not apply to
XMLHttpRequests. One technique is to replace Submit buttons with a "Now updating..." type message so that users do not repeatedly click on buttons while waiting for a response.
Another issue is that users may fail to notice that parts of the page they're viewing have been updated. You can alleviate this problem by using a variety of visual techniques to subtly draw the user's eye to updated areas of the page. Other issues caused by updating the page with Ajax include "breaking" the browser's back button, and the URL in the address bar not reflecting the entire state of the page, preventing bookmarking. See the Resources section for articles that specifically address the usability issues of Ajax applications.
Implementing an Ajax UI in place of a regular forms-based one may dramatically increase the number of requests made to the server. For instance, a regular Google Web search causes one hit on the server, occurring when the user submits the search form. However, Google Suggest, which attempts to autocomplete your search terms, sends several requests to the server as the user types. When developing an Ajax application, be aware of how many requests you'll be sending to the server and the resulting server load this will cause. You can mitigate server load by buffering requests on the client and caching server responses in the client, where applicable. You should also attempt to design your Ajax Web applications so that as much logic as possible can be performed on the client, without needing to contact the server.
Dealing with asynchrony
It's very important to understand that there is no guarantee that
XMLHttpRequests will complete in the order they were dispatched. Indeed, you should assume that they will not and design your application with this in mind. In the shopping-cart example, a last-updated timestamp was used to make sure that newer cart data would not be overwritten by older data (see Listing 7). This very rudimentary approach works for the shopping-cart scenario, but may not for others. Consider at design time how you will deal with asynchronous server responses.
Back to top
There's good news if you're feeling daunted by the complexity of writing a large Ajax application using the techniques demonstrated here. Just as frameworks like Struts, Spring, and Hibernate have evolved to abstract Web application development away from the low-level details of the Servlet API and JDBC, so toolkits are appearing to ease Ajax development. Some of these focus solely on the client side, providing easy ways to add visual effects to your pages or streamlining the use of
XMLHttpRequest. Others go further, providing means to automatically generate Ajax interfaces from server-side code. These frameworks do the heavy lifting for you, so that you can take a more high-level approach to Ajax development. I'll be looking at some of them in this series.
The Ajax community is fast moving, and there's a great deal of valuable information out there. Before reading the next installment in this series, I recommend that you consult the articles listed in the Resources section, especially if you're new to Ajax or client-side development. You should also take some time to study the example source code and think about ways to improve it.
In the next article in this series, I'll discuss the
There is one drawback to this strategy. A few versions of olderbrowsers, such as very early versions of Netscape Navigator and NCSAMosaic, had some trouble with comments. The problems ranged frommangled display to browser crashes. This happened with only a veryfew browser versions, and it's safe to say that very few ofthese browsers are still being operated. Be aware that there are somepeople out there using these particular browsers, and they may wellhave major problems viewing your page if you use these comment tags.
- Applies to
- unordered list and heading will be set to have negative margins:
The larger of the two negative margins (-18px ) is added to the largest positive margin (20px ), yielding (20px-18px = 2px ). Thus, there are only two pixels between the bottom of the list item's content and the top of the paragraph's content. This is what we see in Figure 8-24.
Figure 8-24. Collapsing margins and negative margins, in detail
disc | circle | square | decimal | upper-alpha | lower-alpha | upper-roman | lower-roman | none