Javascript Basics Part 10

By Mark Kahn

You've probably heard the term "AJAX" thrown around recently. Basically it's a fancy name for a technology that's been around for years. Over the past year or so, however, AJAX-style JavaScript has become increasingly popular among many developers and we're starting to see some amazing things come from it. Google Maps and GMail are two of the most well known AJAX applications, but companies all over the web are starting to incorporate it into their sites.

AJAX stands for Asynchronous JavaScript And XML. All it really consists of is JavaScript, just like you would have in any other application, and an XMLHTTP connection to your web server. That's it! The general idea is that when you need to pull data from a server you can just go and get the specific data you need instead of refreshing the entire page.

To start with, AJAX almost always relies on a server-side language such as PHP or ASP. When your users need to get new data, the JavaScript requests it, and the server will probably query a database and then return the data. This data can be returned in several forms. If it is structured, then you will generally have XML or JSON data. If it is very simple data (such as getting a description for an item), you will often see people just writing that data directly to the AJAX response.

Creating an XMLHttp Object

The first thing we need to do when creating an AJAX request is to create an XMLHTTP object. Netscape/Firefox, Opera and other browsers have this object built-in. Internet Explorer uses an ActiveXObject. So we create one function that works for all of these browsers:
if(typeof(XMLHttpRequest)!='undefined'){
	var getXMLHttpObj = function(){ return new XMLHttpRequest(); }
} else {
	var getXMLHttpObj = function(){
		var activeXObjects = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0',
		'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
		for(var i=0; i<activeXObjects.length; i++){
			try{
				return new ActiveXObject(activeXObjects[i]);
			}catch(err){}
		}
	}
}
Any browser that supports the XMLHttpRequest object (including IE7 when it is released) will use this built-in object. Internet explorer 6 and earlier will fail back to Microsoft's XMLHttp ActiveX object. Microsoft has many different versions of this object so we will try them all, starting with the newest one.

Now that we have our XMLHttp object, we will place a request to our server:

var oXml = getXMLHttpObj();

oXml.open('GET', 'getData.php', true);
oXml.onreadystatechange = processingFunction;
oXml.send();

function processingFunction(){
	if(oXml.readyState!=4) return; // our request is not done

	// we process the results here.  More on that later!
}
After the creation of our XMLHttp object, there are 4 additional steps. First we specify the details of our connection with the .open function. The .open function takes 3 arguments: The request type, the URL and a flag that tells the object whether or not to run asynchrounously.

The first argument, the request type, is almost always GET or POST. If you are retreiving data this will usually be GET and if you are submitting a form with AJAX this will often be POST.

The asynchrounous flag is a little different than almost anything else in JavaScript. If this flag is set to false our code continues like any other piece of code, that is it waits for our XMLHttp object to finish doing its thing before moving on. If, however, this flag is set to true, our code continues doing whatever we have after our request. Whenever the request state changes the function defined by onreadystatechange is called.

What's the difference? Well if the async flag is set to false, your browser will completely lock while the request is downloading. If you absolutely need the data before doing anything else, do this. If the flag is set to true then the user can continue to use the webpage, but there is no gaurantee as to when the request comes back. It could come back in 1/2 sec or it could come back in 1 minute. It all depends on what your server is doing and the end user's connection.

When everything is ready to go we send the request. Then we wait. If we are running our request sync with our processing function, defined with onreadystatechange, it will be called several times. It is actually called whenever the state of our request changes. There are various states such as sending and loading data, but all we care about is whether or not the data is done downloading. If the readyState == 4, our request is done, so in any other case we just exit the function.

Now we have our data...but wait, what data do we have?

XML vs JSON vs Text

There are generally three possible ways in which to return your data: XML, JSON or plain text. If you are retreiving data from a database you will probably want to use XML or JSON. Neither is necessarily better than the other. XML is a very widely accepted standard and as such, there are many applications out there that work with XML files. JSON is a newer idea, but is catching on quickly. It is also usually easier to read (for a human) and takes up a bit less bandwidth to send.

Let's say we are writing an application to manage contacts. Our server might be returning a list of people's information. The same data can be expressed in XML or JSON:

XML:

<xml>
	<contacts>
		<person firstname="Joe" lastname="Smith" phone="555-1212" />
		<person firstname="Sam" lastname="Stevens" phone="123-4567" />
	</contacts>
</xml>
JSON:
{contacts:[
	{"firstname":"Joe", "lastname":"Smith",   "phone":"555-1212"},
	{"firstname":"Sam", "lastname":"Stevens", "phone":"123-4567"}
]}
You may notice that the XML notation looks suspiciously like HTML. Well for the most part, it is. HTML and XML are both tag-based languages and they can even be parsed the same way (see the 6th article in this series for more information).

Further, the JSON notation looks suspiciously like plain ordinary JavaScript. JSON stands for JavaScript Object Notation and as such it is just plain ordinary JavaScript.

Either notation can just be sent as plain text from your web server. None of the spacing included in these examples is necessary except for the single spaces between attribute names in the person tags (in the XML version).

The XML format is a collection of tags, very similiar to HTML. You can have any number of tags nested in one-another and each tag can have any number of attributes: ie firstname, lastname and phone in the example above. There are a few things to watch out for, however:

  • Every tag must have a closing tag. <contacts>, for example, is closed with </contacts> below it. The person tags are self-contained. The /> at the end effectively acts as an extra closing tag. We could just as easily have written one of these as: <person ...></person>.
  • XML has a limited character set that you can use. Specifically the following characters are not valid in nodes or attributes and must be replaced:
    • & --> &amp;
    • < --> &lt;
    • > --> &gt;
    • " --> &quot;
    • ' --> &#39;
    The node <group name="Bill & Paul" />, for example, is invalid and must be replaced with <group name="Bill &amp; Paul" />
  • Data coming from your server must be sent with a content-type of text/xml. If you are retrieving a file with an .xml extension this should happen automatically. If you are retrieving data from a script, you must set this manually:
    • For PHP, add the following:
      <?php header('Content-type: text/xml'); ?>
    • For ASP, add:
      <% response.contentType = "text/xml" %>
    • For all other languages, add the equivalent content-type header
    If this header is not set, the responseXML property of the XMLHttp object will be empty (this property will be explained shortly).

JSON has similiar rules to follow, and full documentation on the notation can be viewed at json.org. Simplified, however:

  • Objects start and end with { and } characters respectively
  • Arrays start and end with [ and ] characters respectively
  • All strings are enclosed in double quotes, "
  • " characters in string must be escaped: \"
Put simply, a JSON string has to represent a valid JavaScript object.

Now we will look at how we can parse this data. For the time being, we are just going to create a script to tell us how many contacts we have and alert their information. Let's start with the XML version by returning to a previous piece of code that we left open:

function processingFunction(){
	if(oXml.readyState!=4) return; // our request is not done

	// we process the results here.  More on that later!
}
Once our script gets into the body of our function, the XMLHttp request is done. The XMLHttp object has two methods to return data: responseXML and responseText. Since we are working with an XML file at the moment, we want to use responseXML:
function processingFunction(){
	if(oXml.readyState!=4) return;

	var xmlDoc   = oXml.responseXML;
	var contacts = xmlDoc.selectNodes('/xml/contacts/person');

	alert('There are '+contacts.length+' contacts!');

	for(var i=0; i<contacts.length; i++){
		alert('Contact #'+(i+1)+':\n\n'+
				'First Name: '+contacts[i].getAttribute('firstname')+'\n'+
				'Last Name:  '+contacts[i].getAttribute('lastname') +'\n'+
				'Phone #:    '+contacts[i].getAttribute('phone')    +'\n');
	}
}
We get 3 alerts here. One that tells us there are two contacts, and two more that have the contact information for each person.

Looking at the same script using our JSON text:

function processingFunction(){
	if(oXml.readyState!=4) return;

	var json = eval('('+oXml.responseText+')');

	alert('There are '+json.contacts.length+' contacts!');

	for(var i=0; i<json.contacts.length; i++){
		alert('Contact #'+(i+1)+':\n\n'+
			'First Name: '+json.contacts[i].firstname+'\n'+
			'Last Name:  '+json.contacts[i].lastname +'\n'+
			'Phone #:    '+json.contacts[i].phone    +'\n');
	}
}
As you can see, JSON strings can be transformed into a JavaScript by simply using the eval() command, built in to JavaScript. You should only do this, however, if you completely trust the source of the data. If you do not (if it is coming from anyone other than yourself), you should run it through a JSON Parser just to be safe.

Finally you could elect to return your data in any other straight text format you choose instead of XML or JSON. If you do this you will have to figure out how to parse the data, however. If you only have one piece of data however, such as a comment, this may be a viable option for you.

As for which one to use: XML vs JSON? There's not a whole lot of difference here. XML is a more wide spread format and is transferable to almost any system. If your project is going to be working with external sources, you would probably use XML. JSON is, however, a bit easier to understand and in general it is faster to develop code for than XML. If you are using this for a personal project or starting a new project that doesn't need to interface with other applications, JSON is definitely worth consideration.

A contact list example

You actually have all the tools you need to start writing AJAX applications, but we'll go through a fairly simple example. We are going to write a data grid that pulls the data from three different JSON files. For simplicity, these files have already been generated. In practice these files would likely be generated on the fly by a server-side script.

File 1, File 2, File 3

These files will serve all the data for our AJAX Contact list. Building the contact list is actually very straight-forward: we create a TABLE to hold all of our contacts, and a function to empty and re-populate that table. That's all.

<table cellspacing="1" cellpadding="3" bgcolor="#000000" style="font-family:tahoma;font-size:10px;">
	<tbody id="contactListTable">
		<tr style="background-color:#CCF;">
			<th>First Name</th>
			<th>Last Name</th>
			<th>Phone #</th>
		</tr>
	</tbody>
</table>
function loadContactListPage(n){
	var oXML = getXMLHttpObj();
	oXML.open('GET', '/img/10_json_file'+n+'.txt', true);
	oXML.onreadystatechange = function(){ doneLoading(oXML); }
	oXML.send('');
}

function doneLoading(oXML){
	if(oXML.readyState!=4) return;

	var json  = eval('('+oXML.responseText+')');
	var table = document.getElementById('contactListTable');

	for(var i=table.childNodes.length-1; i>0; i--){
		table.removeChild(table.childNodes[i]);
	}

	for(var i=0; i<json.contacts.length; i++){
		var tr  = document.createElement('TR');
		var td1 = document.createElement('TD');
		var td2 = document.createElement('TD');
		var td3 = document.createElement('TD');

		tr.style.backgroundColor = i%2?'#FFF':'#E6E6E6';

		table.appendChild(tr);

		tr.appendChild(td1);
		tr.appendChild(td2);
		tr.appendChild(td3);

		td1.appendChild(document.createTextNode(json.contacts[i].firstname));
		td2.appendChild(document.createTextNode(json.contacts[i].lastname));
		td3.appendChild(document.createTextNode(json.contacts[i].phone));
	}
}
Demo
First Name Last Name Phone #
Page 1 | Page 2 | Page 3

As you can see from the example above, this is all fairly straight-forward. The majority of our code is actually just needed to create the new rows in our table.

AJAX can be an incredibly useful tool. You can use it to validate forms before submitting them, you can use it to pull data, as in this example, or to do any of a million things you might come up with. It usually shouldn't be the focus of your website, however. In general you should make sure your site is accessible even if people have JavaScript turned off, but there are always some necessary exceptions to this rule.

Enjoy! Our next article is going to be covering JavaScript error handling. See you then!

Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •