Ajax
Ajax is a name for a group of related web development patterns used to create interactive web apps. In a traditional, non-Ajax web app, users browse through the app page by page: each user action results in a request from the web browser for a new page. However, in an Ajax app, user actions result in the updating of a portion of the page based on a small amount of data transferred between the browser and the web server asynchronously. As a result, the app appears much more responsive and consumes far less bandwidth. Although the term Ajax was coined in 2005,[*] similar techniques have been in use since frames were introduced to HTML in the mid-1990s. In those early apps, hidden frames and the IFRAME tag, in Internet Explorer, were used to load HTML documents using JavaScript. These HTML documents contained JavaScript that changed the appearance of the page. In addition, similar functionality could be achieved using Java Applets and browser plug-ins.
[*] See http://www.adaptivepath.com/publications/essays/archives/000385.php.
Although asynchronous capabilities existed with frames, these capabilities were fairly error-prone. For example, if the user clicked the browser's back button, the app could be put into an invalid state. Alternatives to using frames such as Java Applets or browser plug-ins had their own browser compatibility and security issues. As a result, Ajax apps were not common and, where they did exist, were designed for specific user bases or platforms. This all changed when Microsoft introduced the XMLHttpRequest object in Internet Explorer 5 in 2000.
Is Ajax an Acronym?Strictly speaking, Ajax is defined as an acronym for Asynchronous JavaScript and XML. However, the convention is to only uppercase the Ai.e., Ajax not AJAX. Furthermore, as Ajax patterns have gained wider usage among developers, techniques have arisen to accomplish the goals of Ajax without using XML. For example, Google's Ajax apps (Gmail, Google Maps, Google Spreadsheets, etc.) use relatively little XML. It is therefore increasingly clear that Ajax shouldn't be considered an acronym. Or, if it is to be considered an acronym, it's for Asynchronous JavaScript and the XMLHttpRequest object. |
XMLHttpRequest
The XMLHttpRequest object is an object used by a scripting language within the browser (usually JavaScript, but it's not limited to JavaScript) to make an HTTP request. As its name suggests, this object was created to make a request for an XML document. However, there's nothing XML-specific about the object's behavior. XMLHttpRequest is not currently standardized, although current implementations have more or less the same capabilities. There is an effort underway by the W3C to standardize the object's interface and functionality. A working draft of the standard is available at http://www.w3.org/TR/XMLHttpRequest. In Internet Explorer versions prior to 7, XMLHttpRequest is an ActiveX control instantiated like:
var req = new ActiveXObject("Microsoft.XMLHTTP");
In IE 7 and other browsers, it is a JavaScript object instantiated with the new keyword:
var req = new XMLHttpRequest( );
As a result, you'll generally use an if-else construct to create the appropriate object based on the browser:
var req; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); }
XMLHttpRequest can operate in either synchronous mode, in which the script waits for the response to be returned by the server, or asynchronous mode, in which the script is contained to execute after sending the request and a callback method is invoked when the response has been returned. Example 13-8 contains a page that requests an XML document and outputs it as the value of a form field within the body of the HTML page.
Example Synchronous use of XMLHttpRequest
<html> <body> <form ><textarea rows="20" cols="80" ></textarea> </form> <script language="JavaScript"> var req; var xmlarea = document.forms['form'].elements['xmlarea'] if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req == undefined) { xmlarea.value = "XMLHttpRequest object not available."; } else { req.open("GET", "/ch13-servlet/booklist-xml", false); // third param = false means use synchronous mode req.send(null); // check the status if (req.status == 200) xmlarea.value = req.responseText; else xmlarea.value = "Got Response Code: " + req.status; } </script> </body> </html> |
Example 13-9 does the same thing, but in asynchronous mode.
Example Asynchronous use of XMLHttpRequest
<html> <body> <form ><textarea rows="20" cols="80" ></textarea> </form> <script language="JavaScript"> var xmlarea = document.forms['form'].elements['xmlarea']; var req; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req == undefined) { xmlarea.value = "XMLHttpRequest object not available."; } else { req.open("GET", "/ch13-servlet/booklist-xml", true); // third param = true means use asynchronous mode req.onreadystatechange = docLoaded; req.send(null); } function docLoaded( ) { if (req.readyState == 2) { xmlarea.value = "Waiting..."; } if (req.readyState == 4) { xmlarea.value = "Got Response..."; // just for effect, update the textarea after waiting a second setTimeout("updateTextArea( )",1000); } } function updateTextArea( ) { if (req.status == 200) xmlarea.value = req.responseText; else xmlarea.value = "Got Response Code: " + req.status; } </script> </body> </html> |
In asynchronous mode, the XMLHttpRequest object needs to have a callback function set using the onreadystatechange property. When this function is called, it checks the readyState property to determine what the current state of the request is. Possible values for this property are contained in Table 13-1. Note that the callback function may not be called for each of these states.
Table 13-1. Possible values for XMLHttpRequest's readyState property
Value | Meaning |
---|---|
0 | Uninitialized |
1 | Open |
2 | Sent |
3 | Receiving |
4 | Loaded |
|
These examples simply include the contents of an XML document into the page when it's first loaded. Example 13-10 goes a step further and allows the user to switch between two documents without reloading the page.
Example Requesting different documents based on user actions
<html> <body> <form ><textarea rows="20" cols="80" >No Books.</textarea> </form> <script language="JavaScript"> var xmlarea = document.forms['form'].elements['xmlarea']; var req; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } function loadBooks(filename) { if (req == undefined) { xmlarea.value = "XMLHttpRequest object not available."; } else { xmlarea.value = "Waiting..."; req.open("GET", "/ch13-servlet/"+filename, true); req.onreadystatechange = docLoaded; req.send(null); } } if (req.readyState == 4) { if (req.status == 200) xmlarea.value = req.responseText; else xmlarea.value = "Got Response Code: " + req.status; } </script> <a href="javascript:loadbooks('books.xml')">Load Books</a><br/> <a href="javascript:loadbooks('morebooks.xml')">Load More Books</a><br/> </body> </html> |
When this page is first loaded, the textarea contains the string "No Books." The user can then click on one of the links to populate the textarea. Figures 13-6 and 13-7 show the page upon load and after clicking the "Load More Books" link, respectively.
Page immediately after loading

Page after clicking Load More Books

Using DOM with Ajax
In addition to the responseText property containing the response as a string, XMLHttpRequest has a responseXML property that contains the response as a DOM object. We can use the DOM API to extract values from this object instead of just dumping the XML into the page, as we'd done above. The HTML page in Example 13-11 contains a div tag whose content is populated with the title and authors of each tutorial in an XML file. When one of the file selection links is chosen, the default text is overwritten with the tutorial list by using the innerHTML property. We use the getElementsByTagName( ) DOM method as well as various DOM properties.
Example DOM document access in JavaScript
<html> <body> <div > No tutorials Loaded. </div> <hr/> <script language="JavaScript"> var xmlarea = document.getElementById('xmlarea'); var req; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } function loadBooks(filename) { if (req == undefined) { xmlarea.innerHTML = "XMLHttpRequest object not available."; } else { xmlarea.innerHTML = "Waiting..."; req.open("GET", "/ch13-servlet/"+filename, true); req.onreadystatechange = docLoaded; req.send(null); } } function docLoaded( ) { if (req.readyState == 4) { doc = req.responseXML; newValue = "Books:<br/>\n"; tutorials = doc.getElementsByTagName("book"); for (i = 0; i < tutorials.length; i++) { tutorial = tutorials.item(i); var title; var author; for (j = 0; j < tutorial.childNodes.length; j++) { node = tutorial.childNodes[j]; if (node.nodeName == "title") { title = node.firstChild.nodeValue; } else if (node.nodeName == "author") { author = node.firstChild.nodeValue; } } newValue = newValue + (i+1) + ") " + title + " by " + author + "<br/>\n"; } xmlarea.innerHTML = newValue; } } </script> Choose a file list:<br/> <a href="javascript:loadbooks('books.xml')">books.xml</a><br/> <a href="javascript:loadbooks('morebooks.xml')">morebooks.xml</a><br/> </body> </html> |
shows the page as it displays when initially loaded. The page after selecting books.xml can be seen in . Note that the div element is resized automatically and, as a result, the links are pushed down.
DOM page before selecting a file

DOM page after selecting a file

If you have a solid understanding of the DOM API in Java, you should be able to apply this knowledge to using DOM in JavaScript. The DOM language bindings for ECMAScript (the standard scripting language of which JavaScript is a derivative) are defined by the W3C at http://www.w3.org/TR/DOM-Level-3-Core/ecma-script-binding.html. For additional details on the JavaScript DOM API, please consult JavaScript: The Definitive Guide by David Flanagan (Oracle).
Using XSLT with Ajax
Internet Explorer and Mozilla Firefox both support XSL transformations through JavaScript. Unfortunately, as with the XMLHttpRequest object, the transformation support is accessed in a different way in each browser. In IE Internet Explorer, DOM objects have a method named transformNode( ), which is passed a DOM Document object containing the stylesheet:
transformOutput = element.transformNode(xslDocument);
The output of a transformation can be a string, as above, or a DOM object. In Firefox, there is a JavaScript object called XSLTProcessor to which stylesheet documents are added before a transformation is done:
xsltProcessor = new XSLTProcessor( ); xsltProcessor.importStylesheet(xslDocument); transformOutputDoc = xsltProcessor.transformToFragment(element, document);
The output of a transformation in Firefox can either be a DOM fragment or a DOM document. The page in Example 13-12, shown in the next section, contains the same functionality using XSLT as Example 13-11 did with DOM. In this example, you can see how the output of the transformation is used differently in Internet Explorer and Firefox.
<html> <body> <div > No tutorials Loaded. </div> <hr/> <script language="JavaScript"> var xmlarea = document.getElementById('xmlarea'); var req; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } req.open("GET", "/ch13-ajax/authortitle.xsl", false); req.send(null); var xsldoc = req.responseXML; function loadBooks(filename) { if (req == undefined) { xmlarea.innerHTML = "XMLHttpRequest object not available."; } else { xmlarea.innerHTML = "Waiting..."; req.open("GET", "/ch13-servlet/"+filename, true); req.onreadystatechange = docLoaded; req.send(null); } } function docLoaded( ) { if (req.readyState == 4 && req.status == 200) { xmldoc = req.responseXML; if (window.ActiveXObject) { xmlarea.innerHTML = xmldoc.transformNode(xsldoc); } else if (window.XSLTProcessor) { processor = new XSLTProcessor( ); processor.importStylesheet(xsldoc); xmloutput = processor.transformToFragment(xmldoc, document); xmlarea.innerHTML = ""; xmlarea.appendChild(xmloutput); } else { xmlarea.innerHTML = "XSLT not available in your browser."; } } } </script> Choose a file list:<br/> <a href="javascript:loadbooks('books.xml')">books.xml</a><br/> <a href="javascript:loadbooks('morebooks.xml')">morebooks.xml</a><br/> </body> </html>
Posting XML to the Server
In the examples above, the requests made with XMLHttpRequest have all been basic URLs. We can easily add simple parameters to these requests using the query string, such as http://www.example.com/servlets/stock?s=IBM. For more complex parameters, XMLHttpRequest supports posting content as the body of the request, using the HTTP POST method. One use for this capability is to post XML documents to an app running on the server. To do this, you should set the Content-Type header of the request to be text/xml and pass the XML document, either as a string or a DOM object, to the XMLHttpRequest object's send( ) method.
Creating an XML document in JavaScript
To generate the XML document for the request, you could use simple string concatenation such as:
req.send("<search><name>" + document.getElementById("name").value + "</name><year>" + document.getElementById("year").value + "</year></search>");
The JavaScript necessary to construct a document with concatenation can quickly become confusing and error-prone as nothing stops you from generating ill-formed documents. To ensure that well-formed documents are produced, you should use the DOM capabilities in JavaScript. As with XMLHttpRequest, DOM Document objects are created as ActiveX objects in Internet Explorer and through a native JavaScript API in other browsers. To create a DOM Document in Internet Explorer, you first create the empty document and then the root element:
doc = new ActiveXObject("Microsoft.XMLDOM"); doc.appendChild(doc.createElement("search"));
And in Firefox and other browsers, the document is created already populated with a root element:
doc = document.implementation.createDocument(null, "search", null);
The createDocument( ) method accepts a namespace URI and a DTD in addition to the root element name.
Submitting the XML document
Once you have built the document, either as a string or a DOM object, it gets passed to the send( ) method of XMLHttpRequest. Example 13-12 contains a simple HTML form whose submit button results in posting the form fields as an XML document.
Example Submitting form data as XML
<html> <body> <h1>Book Search</h1> <form onsubmit="search( ); return false;"> Name: <input type="text" /><br/> Year (optional): <select > <option value="notselected">...select one...</option> <option value="2001">2001</option> <option value="2002">2002</option> <option value="2003">2003</option> <option value="2004">2004</option> <option value="2005">2005</option> </select><br/> <input type="submit" /> <hr/> Search Results:<br/> <textarea rows="3" cols="50" readonly="true"></textarea> </form> <script language="JavaScript"> function search( ) { var req; var form = document.forms['form']; if (window.XMLHttpRequest) { req = new XMLHttpRequest( ); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req == undefined) { document.getElementById("results").value = "XMLHttpRequest object not available."; } else { req.open("POST", "/ch13-ajax/post", false); req.setRequestHeader("Content-Type", "text/xml"); postDoc = makePostData( ); req.send(postDoc); // check the status if (req.status == 200) document.getElementById("results").value = req.responseText; else document.getElementById("results").value = "Got Response Code: " + req.status; } } function makePostData( ) { var doc; if (window.ActiveXObject) { doc = new ActiveXObject("Microsoft.XMLDOM"); doc.appendChild(doc.createElement("search")); } else { doc = document.implementation.createDocument(null, "search", null); } nameElement = doc.createElement("name"); nameText = doc.createTextNode(document.getElementById("name").value); nameElement.appendChild(nameText); doc.documentElement.appendChild(nameElement); yearElement = doc.createElement("year"); yearText = doc.createTextNode(document.getElementById("year").value); yearElement.appendChild(yearText); doc.documentElement.appendChild(yearElement); return doc; } </script> </body> </html> |
|
When building a servlet that accepts these requests and parses the request XML document, you can use either the Reader or InputStream from the request, accessed with geTReader( ) and getInputStream( ), respectively. Although it doesn't actually do any searching, Example 13-13 contains a servlet that accepts the XML document produced by Example 13-12 and echoes the search terms back to the browser. We use JDOM's XPath support to extract the search terms from the request document.
Example Servlet to accept XML posts
package javaxml3.ch13; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jdom.Document; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; public class PostServlet extends HttpServlet { private SAXBuilder builder = new SAXBuilder( ); private XPath nameXPath; private XPath yearXPath; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (!"text/xml".equals(request.getContentType( ))) { response.getWriter( ).println("Please post as text/xml."); } else { try { Document doc = builder.build(request.getReader( )); StringBuffer buff = new StringBuffer( ); buff.append("You searched for name '" + nameXPath.valueOf(doc) + "'"); String year = yearXPath.valueOf(doc); if (!"notselected".equals(year)) { buff.append(" and year '" + year + "'"); } buff.append("."); response.getWriter( ).print(buff.toString( )); } catch (JDOMException e) { response.getWriter( ).print( "Error getting search terms: " + e.getMessage( )); } } } public void init( ) throws ServletException { try { nameXPath = XPath.newInstance("/search/name/text( )"); yearXPath = XPath.newInstance("/search/year/text( )"); } catch (JDOMException e) { throw new ServletException("Unable to create XPaths", e); } super.init( ); } } |
Putting the HTML and servlet together gives us the output pictured in .
Result of XML post

This section has contained a quick overview of the use of XML in Ajax apps. There's a lot more involved in creating a complete Ajax app. Ajax is a rapidly growing area and there are a wide variety of online sources for more information, from blogs like Ajaxian.com to developer sites created by Mozilla and Microsoft. Dozens of Ajax-related tutorials are available for sale including, we should note, Head Rush Ajax by Brett McLaughlin (Oracle).