Getting Started with AJAX
See the XML demo page for the finished version of the code.Using XML
In the previous example, the server returned a simple text string in response to a request. But what if you need to handle more data? Or structured data? The XMLHttpRequest object can automatically parse XML sent in response to a server request.
Of course, you first need a server-side script that outputs an XML document. The getZipCodes.asp script does just that. Similar to the server-side script in the last example, this one will take a city and state and return a set of ZIP codes for that city in XML format. You can try it with the link below:
getZipCodes.asp?city=las+vegas&state=nv
For our next example, we'll use this data to dynamically populate a drop down box given a city and state entered by the user. Try the demo, enter a U.S. city and state and click on the "Lookup Zip Codes" link. Once the list is loaded, you can select one and it will be copied into the ZIP code field.
Looking at the source, the code to initiate the request is similar to the previous example. But before it initates the request it first does some validation to ensure the user has entered both a city and state, clears the ZIP code from field and removes any existing entries in the drop down list before hiding it from the user.
var zipCodeLookup = getXMLHttpRequest(); function initiateZipCodeLookup(event) { // Clear the status text. setStatusText(""); // Check for a city and state. var city = document.forms[0].elements["city"].value; var state = document.forms[0].elements["state"].value; if (city.length == 0 || state.length != 2) { setStatusText("Enter a city and two-letter state abbrev."); return; } // Clear the current zip code. document.forms[0].elements["zipCode"].value = ""; // Hide the drop down list. document.forms[0].elements["zipCodeList"].style.visibility = "hidden"; // Clear the zip code drop-down list. while (document.forms[0].elements["zipCodeList"].options.length > 0) document.forms[0].elements["zipCodeList"].remove(0); // Perform an asynchronous request to get a list of zip codes for // that city and state. var url = "getZipCodes.asp?city=" + encodeURI(city) + "&state=" + encodeURI(state); zipCodeLookup.onreadystatechange = zipCodeReadyStateChange; zipCodeLookup.open("GET", url, true); zipCodeLookup.send(null); }
Note the use of the built-in encodeURI()
function on the form
field values. This ensures that no invalid characters appear in the query
string we'll be sending to the server.
The function that handles the onreadystatechange
event is
also similar. The difference is in how the returned data is processed. The XML
looks something like:
<zipCodes city="Las Vegas" state="NV"> <zipCode>89101</zipCode> <zipCode>89102</zipCode> <zipCode>89103</zipCode> <zipCode>89104</zipCode> ... </zipCodes>
The responseXML
property of the XMLHttpRequest object is
a DOM document. You can access all its nodes, attributes and node values
within your JavaScript just like the DOM of a web page.
Given the above XML, zipCodeLookup.responseXML.documentElement
will be the node for the <zipCodes> tag while
zipCodeLookup.responseXML.getElementsByTagName("zipCode")
would
return an array of nodes representing the <zipCode> tags.
In this demo, the code that handles the processing of the XML returned
from the server first looks at the root node to extract the values of the
city
and state
attributes:
var xmlDoc = zipCodeLookup.responseXML; // Copy the city and state attributes from the root XML node to the // appropriate form fields. var city = xmlDoc.documentElement.getAttribute("city"); var state = xmlDoc.documentElement.getAttribute("state"); if (city.length > 0 && state.length > 0) { document.forms[0].elements["city"].value = city; document.forms[0].elements["state"].value = state; // Clear the current zip code. document.forms[0].elements["zipCode"].value = ""; }
These are then used to update the corresponding city and state form fields on the page. This may seem pointless since the user has just typed in the city and state, but it does ensure proper capitalization of the text and serves as an example of how to extract that data from the XML.
Next, it sets up the list of ZIP codes by looping through all the <zipCode> tags in the XML.
// Get all the zip code tags returned from the request. var els = xmlDoc.getElementsByTagName("zipCode"); // Add a dummy option to the zip code drop-down list. var option = document.createElement("OPTION"); option.text = "Select one..."; option.value = ""; try { document.forms[0].elements["zipCodeList"].add(option, null); } catch(ex) { // For IE. document.forms[0].elements["zipCodeList"].add(option); } // Add an option to to the drop-down list for each zip code // returned from the request. for (var i = 0; i < els.length; i++) { option = document.createElement("OPTION"); option.text = option.value = els[i].firstChild.nodeValue; try { document.forms[0].elements["zipCodeList"].add(option, null); } catch(ex) { // For IE. document.forms[0].elements["zipCodeList"].add(option); } } // Show the drop down list and set focus on it. document.forms[0].elements["zipCodeList"].style.visibility = ""; document.forms[0].elements["zipCodeList"].focus();
For each node, it extracts the text within and creates a new OPTION element which is added it to the SELECT list. That list is then made visible to the user.
The SELECT element has an onchange
event handler assigned to
it. This function copies the selected option to the ZIP code field.
function setZipCode(event) { // Copy the zip code selected from the drop-down list to the text // zip code field. var n = document.forms[0].elements["zipCodeList"].selectedIndex; document.forms[0].elements["zipCode"].value = document.forms[0].elements["zipCodeList"].options[n].value; // Clear the current selection. document.forms[0].elements["zipCodeList"].selectedIndex = -1; }
Posting Data on an HTTP Request
See the POST demo page for the finished version of the code.Both of the previous demos used a query string on the request URL to pass data to the server-side script. You can also pass data using the POST method, which is how a typical HTML form submission works.
This demo does the same thing as the last one,
except that it uses the POST method to pass the data to the web server. The
only difference in the code is in the initiateZipCodeLookup()
function:
// Encode the data to be POSTed. var city = encodeURI(document.forms[0].elements["city"].value); var state = encodeURI(document.forms[0].elements["state"].value); // Make the call to get a list of zip codes for that city and state. var url = "getZipCodes.asp" // Perform an asynchronous request to get a list of zip codes for that // city and state. var url = "getZipCodes.asp"; zipCodeLookup.onreadystatechange = zipCodeReadyStateChange; zipCodeLookup.open("POST", url, true); zipCodeLookup.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); zipCodeLookup.send("city=" + city + "&state=" + state);
Note that there is no query string appended to the URL, the call to the
open()
method uses "POST" instead of "GET" and the
send()
call includes a string of data.
That string of data is in the exact same format as the query string used previously. That is, name1=value1&name2=value2.... We do have to add an additional step, setting the "Content-Type" header to "application/x-www-form-urlencoded" which tells the server what to expect. We do not have to explicitly set a "Content-Length" header however, as the XMLHttpRequest object will automatically add this based on the amount of data sent.
It's important to point out that you must first call the
open()
method before you can call setRequestHeader()
,
otherwise an error will occur.
You can use other data formats as well, even XML. It all depends on what format the target script or CGI program on the web server expects.
Next, we'll look at some code that makes it easier to perform requests and process the responses so you can focus on putting the technology to use.