Close Window

Print Story

What Is AJAX?

(October 7, 2005) - AJAX isn't a technology, or a language, and there's no recipe to implement it; it's just a combination of various components to achieve something you otherwise couldn't: asynchronous http requests. However, since early 2005, when Google and Flickr popularized the concept, its use has grown rapidly.

The name AJAX is short for Asynchronous JavaScript and XML. It uses the JavaScript XMLHttpRequest function to create a tunnel from the client's browser to the server and transmit information back and forth without having to refresh the page. The data travels in XML format because it transmits complex data types over clear text.

AJAX uses XHTML for the data presentation of the view layer, DOM, short for Document Object Model, which dynamically manipulates the presentation, XML for data exchange, and XMLHttpRequest as the exchange engine that ties everything together.

Because of these requirements, AJAX works on I.E. 5.0+, Mozilla 1.0+, Firefox 1.0+, Netscape 7.0+, and Apple added it to Safari 1.2+.

Traditional HTML sends a request to the server, which processes it and either returns a static HTML page or dispatches the request to some scripting language such as ColdFusion, which creates and returns an HTML page for the browser to render. When this method has to retrieve new data from the server it has to repost and reload another HTML file. In many cases perhaps only a small portion of the returned HTML code varies and the shell itself remains the same resulting in huge overhead because the data has to be downloaded every time.

Some classic examples of applications that would benefit from AJAX are searching for information and displaying it back in a table, related select dropdowns, or checking if a user exists before submitting an entire form.

As we can see, AJAX offers many advantages over traditional HTML applications, but we shouldn't overestimate it. Because the data is JavaScript-driven, one of the main drawbacks is that search engines won't index any of the dynamically generated content. It's definitely not SEO-friendly.

People familiar with MVC will have a better grasp of the concept. Though details of MVC are outside of the scope of this article, the three defined components are Model, View, and Controller. The controller mediates between the data model and the view. It responds to events, which are usually actions by users, and changes the view or model as appropriate. The view consists of the HTML. JavaScript reacts to events triggered by the user and alters the existing rendered content with DOM. ColdFusion will be our model layer and can consist of one or more files.

Building an AJAX platform or engine from scratch can be a difficult and lengthy procedure. There are many AJAX engines available for download and you're welcome to use any of them. The only difference between implementations will be the data encoding, transmission, and decoding methods. The views and models of the MVC will be the same. My examples will be based on CFAJAX, a community-driven Open Source project. One of the problems with CFAJAX is its poor documentation. There is no manual or even a complete FAQ. So I will explain how to set it up step-by-step and work around its downside.

To use AJAX you'll need to really know JavaScript and DOM. But by the end of this article you'll be able to set up AJAX, a ColdFusion model, make basic calls, and exchange simple data. As the applications grow and become more complex, the AJAX engine will remain the same, and the CF model will have more functions, but your JavaScript will have to manipulate more and more objects and that's where it's really at.

Enough chatter, let me show you how it works.

First, go to www.indiankey.com/cfajax/project.asp and download cfajax.1.2.zip (see AjaxCFC for an improved framework). This file contains the core engine, some utilities, and some examples. Let's set up a folder in your Web root or whatever accessible folder you like called 'ajax.' Put the 'core' folder located in the cfajax zip file inside your 'ajax' folder. There are only two important files in this folder: 'engine.js' and 'cfajax.cfm.'

The engine.js contains the whole AJAX object that we'll use as our tunnel and cfajax.cfm has some basic functions that your ColdFusion model will have to include to decode the AJAX packet. Other files, not so core anymore, are 'util.js.' which contains a series of DOM functions to facilitate HTML manipulation when the server response is received, 'rico.js,' used for a built-in accordion example, and 'settings.js,' which aren't really settings, only the location of your ColdFusion model and an error-handler function. The only reason why this file exists is to hide the location of your ColdFusion file should someone open and view the source of your HTML file, which in my opinion is counter-productive because you have to edit this file and add a location variable every time you want to use AJAX with different models. The security should be built into the ColdFusion file.

Some people will claim that they can provide you with AJAX functionality without writing a single line of JavaScript; I disagree. Although you could use ColdFusion libraries to generate JavaScript, the results will be limited to the functionality provided. AJAX means asynchronous JavaScript and XML, not ColdFusion. So if you want to use AJAX effectively and provide solutions to new problems, you should learn JavaScript.

Now that we have our CFAJAX in place, let's create an index.cfm file and a model.cfm file in your ajax folder. For larger applications I would store the views in a 'views' folder and models in a 'models' folder, but I digress. Shall we concentrate on the basic example?

Open index.cfm and include the 'core/engine.js' file. Then create a 'getGreetings' and 'getGreetings_result' function. We'll call getGreetings onLoad for now, and the results function will just alert the response.

The 'engine.js' file creates an object called DWREngine; it means Direct Web Remoting. We will mainly be using a method called '_execute.' Execute takes four or more arguments. The first argument is the ColdFusion model location, then a queryString, a methodName, and a callback function, which is the JavaScript function that will be called when we get a response from the server. Execute also takes some optional arguments. It's not documented, but Execute will take any number of arguments, which will be parameters to be passed to the called method, and they have to be put between the third and fourth argument. I'll show you an example later.

Right now the file looks like this:

Our model.cfm will be extremely simple. All we need to do is include the 'core/cfajax.cfm' file and a getGreetings function:

model.cfm
<cfinclude template="core/cfajax.cfm">
<cffunction name="getGreetings" returntype="string">
  <cfreturn "Today is " & DateFormat(now(),'MMMM DD') & ", Greetings." />
</cffunction>

Well, that was easy; we just finished our first AJAX application.

Now let's create a small application that could actually benefit you. How many times have you created a registration form that can validate almost everything client-side by using JavaScript, but the username has to be validated upon submission, and if it already exists, you either have to abort and use JavaScript for the alert and send the client back, or cflocate and populate all the form fields by using the session. Wouldn't it be great if we could avoid all that and simple check the username as another JavaScript call? And not even think of creating an existing username array and have it local in the registration form?

It 's not that much different from the file we have. Let's modify the index.cfm file a little. We'll create a basic user registration form with a single fieldname called user and we'll pass that value to the AJAX call. The tricky part here is that AJAX is asynchronous, which means that the function won't return the value you need. Instead the callback function will get called on a different thread. Not to worry, I'll demonstrate how this can be done.

model.cfm
<cfinclude template="core/cfajax.cfm">
<cffunction name="userExists" returntype="boolean">
   <cfargument name="event">
   <cfset var return = false />
   <cfif ListFindNoCase('rob,john,paul',event)><cfset return = true /></cfif>
   <cfreturn return />
</cffunction>

Index.cfm now contains a user registration form. On submit, we'll call checkUser(). Note that we must actually call it with a return parameter or we'll always return false! No matter what happens, the form won't get submitted the traditional way. Note that I included 'utils.js' only to call the 'useLoadingMessage' function, which imitates the Gmail loading message while AJAX makes its round trip. 'Execute' sets a callback function, which checks for the ColdFusion return. If true, we'll display an error message, and if the user doesn't exist, we'll manually submit the form by using the JavaScript submit() function. The only difference in the execute call is that we pass the form value to the ColdFusion model. The CFM page is straightforward: all we're doing is a dummy check against a hard-coded list. This is the place where you would put your queries or invoke your components.

You should now be able to set up an AJAX engine, a simple HTML view, make a call, listen, process, and respond using ColdFusion, and process the response in your callback function. In the next part of this article, I'll explain how to pass complex objects by using WDDX serialization, populate tables, use innerHTML properties for advanced JavaScript view manipulations, and provide a full internal rotating banners application that tracks impressions and clicks. I will also cover cross-browser compatibility and offer some little tricks to make your AJAX application as widely compatible as possible.

CFAJAX allows you to send complex objects, but for some reason it's extremely difficult to receive and interpret them on the ColdFusion side. For this reason I came up with a much simpler and straightforward way: WDDX serialization.

This concept may be familiar to some of you. WDDX stands for Web Development Data Exchange and Allaire created it in 2001 to solve problems in exchanging data between Web applications. In a nutshell, WDDX is a technology that facilitates exchanging complex objects over XML. WDXX supports Booleans, numbers, strings, date-time, arrays, structures, and record sets. Modules for WDDX support exist in various languages, including but not limited to ColdFusion, Perl, Java, JavaScript, ASP, .NET, and PHP.

A JavaScript WDDX component is included in the cfide/scripts folder of every ColdFusion installation. You can locate it at /cfide/scripts/wddx.js.

Complex Object Example
Now I'll show you how to use it. Listing 1 shows a simple example in which I created a complex object in JavaScript - a structure that contains an array of structures - and serialized it before sending it to ColdFusion. All you have to do is initialize a new WDDX serializer and serialize the complex object. You can see in Listing 1 how simple it is; you don't need to know the structure of the packet.

Notice the line "DWREngine._execute(_cfscriptLocation, null, ' wddxTest', oWddx.serialize(_o), testResult);". Here the first argument is the location of the ColdFusion model; the wddxTest is the function to be called; the argument is being serialized by our JavaScript component; and the testResult is the callback function.

Listing 2 shows how simple it is to receive the call. The function takes only one argument: the WDDX packet. This packet is not an object; it's actually an XML string. Listing 2 returns it intact just so you see exactly what's happening behind the scenes, and the callback function alerts the return packet. If you run my example, you'll see that the XML string is being alerted to the screen by the testResult function.

Trick 1
Here is a very important cross-browser note for you. Pay special attention to the URLDecode function in the ColdFusion listener (see Listing 2). I found that if you don't use it, the code will work just fine in IE, Firefox, and Netscape, but it will break in Safari for Mac users. I learned this the hard way, so here I am sharing the trick. For some reason, Safari URL-Encodes the XML packet before sending it and ColdFusion cannot decode it, making the argument impossible to de-serialize. Ideally, you'll test your code in as many environments as possible before you go live, so remember this and it may save you some debugging time.

Login Example
I'll now demonstrate a login example and some useful debugging techniques. Sometimes you'll find that the user is navigating your site and he is allowed to log in by using a form that is always available, either in the top or side navigation. Sometimes the user just posts a form, for example, a search products form, and then decides to log in. This may or may not be a problem, but if you allow him to post just the login form, you will lose all other existing form variables. One solution, you may be thinking now, is to loop through the form collection in the login form and create hidden fields; it may work in some cases, however, in other cases such as add-to-cart or checkout, resubmitting the form may cause duplicate process pages. Using cflocate after each process page is a good practice, but I am digressing and won't get into that.

How about adding some of the concepts we learned in this article? How nice would it be to let the user know if her username or password does not match any existing one without refreshing the page? Or even more! How about logging the user in, hiding the login form, and adding her login status without refreshing the page, and thus, without resubmitting, redirecting, or even losing focus of the current item she may be seeing.

This time we'll send the user and password to the ColdFusion model and expect an array for the response. The array will have a "success" status: in case of error, a message; and in case of success, the name of the user. We could also pass a structure, but you'll find that if you pass a structure back, JavaScript will interpret it as an array or keys and values. Then you'll have to loop through the array and assign the values to the keys. An alternative could be using WDDX, but this time to encode the packet before sending it back to JavaScript and use the WDDX component in JavaScript to deserialize it.

Sometimes it's not that easy to know exactly how the structure that ColdFusion sent is being interpreted by JavaScript. In these cases, I always refer to the same debugging method: I loop over the entire scope or collection to find what is being sent back. Listing 3 shows a simple one-line loop that will do the trick. Try to return a structure and see for yourself the way it's being passed back.

Let us continue with our login example. The ColdFusion model will return an array of two elements: array[1] will be the success variable (true or false), and array[2] will be the error message in case of an error, or the name of the user in case of success. For the sake of this article, the model just checks for a static user and password; however, this is exactly where your login logic should be. The trick is to update the session in the model in the background and just send back to JavaScript what it needs for the presentation layer. For instance, you could add the User-ID for the session, and send back the name and last name so it can be displayed in the left navigation.

After the user successfully logged in, we will make the login form disappear and add a simple message that reads "logged in as %name%". We will do this by using the JavaScript innerHTML function. The innerHTML function lets you modify the source code on the fly. Our form was placed inside a DIV layer that is used as a holder and, after the login, we will change the code of the holder to display the new status. When using this method, make sure that the navigation does not have to change upon login, or, if it does, you may modify the navigation too by using innerHTML as well. If you code in an object-oriented fashion, your navigation would be generated by an object you may call in the login function and send the generated HTML back to the JavaScript controller, which will replace the existing one by using innerHTML functions.

Content Example
Another great advantage of AJAX is that it improves load time. For example, imagine a typical site: it has a design frame and content in the center area. Every click has to reload the entire frame to update the content. Ideally, you wouldn't have to transfer the code for the frame and download any of its graphic components again. Caching certainly helps, but AJAX can make it even faster. Listings 4 and 5 show a simple example in which the content is being generated in the ColdFusion model and passed back to the JavaScript controller. For simplicity, in this example I actually added the content directly in the Model.cfm page. In real-life examples, the ideal way would be to actually include a view template with a cfinclude inside the cfsavecontent tag; by doing that your views will not depend on the AJAX component. Perhaps you won't see a huge speed difference just by running this example; this is due to the fact it doesn't have any design elements. As an experiment, try to add a full design frame to my example with an average page weight of 100k or 200k in graphics and compare load times.

Trick 2
Observe that when you pass back HTML content to JavaScript, you have to URL-Encode the content (see Listing 7). If you try to pass back the HTML tags without encoding it, the AJAX calls will break without notice or error messages. In the receiving counterpart, you need to decode the HTML and this is achieved by using the unescape function as shown in Listing 6.

The drawback of this method is that it completely kills search engine friendliness. Search engines will not execute JavaScript calls and will not index your content. As a rule of thumb, I try to keep all front-end related content as SEO friendly as possible. You can use these examples for back-end related purposes. For example, gmail was written completely in AJAX. Notice that you can read and write e-mails and the site will never refresh and the speed is different over hotmail or any other Web mail application.

Table Example
Next, I'll cover looping over an AJAX record set and populating tables. Although you could generate the table and send the rendered HTML by using my previous content example, by using this technique, you'll delegate the load to the client browser instead of keeping it in the server.

I will introduce now a few DOM functions: createElement, createTextNode, setAttribute, appendChild, and removeChild. The concept here is to receive a recordset from a ColdFusion function and create the HTML by using DOM functions instead of the HTML tags.

In this example, I'll only demonstrate the JavaScript part that builds the table. If you look at Listing 8, you'll see an empty table with an ID in the "tbody" tag. This "tbody" tag is extremely useful when you have additional elements such as column headers in the "thead" tag. The "tbody" allows us to reference that section directly when adding and deleting elements.

The logical process that I follow in my pages is showing a "please wait" DIV when the user submits the request. At this point I make the AJAX call, send the request parameters, and wait for the response. The response will trigger the callback function, which immediately executes the "clear_table" function. This function loops over each row in the "tbody" and calls the DOM "removeChild" function. This will clear the results from the previous call. After I finished emptying the table, we proceed to populate it with the new recordset. If you look at the "showTable" function, you'll find two nested loops: one for each row and one for each column. Looping over each column is optional and up to you. Traditional ColdFusion programmers may prefer to loop over each row and manually code each column to their needs. Personally, I like to avoid having to write the same code over and over if I can help it. In my example, I created an array called "r" that contains the columns that I want to display. After you finish populating the table with the new recordset, you may remove the "please wait" message and the process is over.

Populating the table is actually rather simple: first I loop over each row from the recordset and create a "TR" element by using createElement('tr'); then in the nested loop I create the "TD" element for each column by using createElement('td'). The text is then evaluated in the following line "currenttext=document.createTextNode(eval('o.' + r[i] + '[j]'));". Here the "eval" function is resolving the recordset, then the column name, and then the position. For instance, the first row, first column, will read "o.uname[0]".

Creating the links is not as simple as typing "<a>". You will need to create an "A" element by using createElement('a'), and then use the setAttribute to add the href attribute.

After all is said and done, all that's left to do is to append each element to its parent. First you append the text node to the "a" element, then the "a" to the "td", then the "td" to the "tr", and finally the "tr" to the "tbody".

CFAJAX includes some utilities that facilitate this process but, the truth is, you will need to learn DOM JS if you really want to take control. For example, the example in Listing 8 only adds a link to the first column, and all the rest are just text.

Related Options Example
My last example will explain a useful built-in function with CFAJAX: related options (see Listing 9). How many times have you had to load enormous arrays of options to your HTML template to achieve this? Wouldn't it be great if you could load the dependent options only after the main option has been selected? CFAJAX includes two handy functions: "removeAllOptions" and "addOptions". These two functions will drive the JavaScript work to achieve related options to zero.

I hope the community doesn't mind, but I'll use the example from their site to demonstrate how this is achieved.

First, we'll have a brand dropdown that will call a JavaScript function called "getBrand" on its "onChange" trigger. All this function does is send ColdFusion the value of the current selected brand, and ColdFusion will return an array of values.

The array actually contains value pairs, which are the key, and the value separated by commas. It's important to pay attention to the hint value of the ColdFusion function; in this example, it's hint="type='keyvalue' jsreturn='array'", which is actually used in the callback function to set the expected value types. You can tell JavaScript the complex type of the return, set it to receive value pairs, and optionally set the delimited of the pairs. By default, it is expecting a comma for the delimiter.

The callback function cannot get any simpler. "getBrandResults" performs only two functions: DWRUtil.removeAllOptions("model"), which removes all current options from the model select component, and DWRUtil.addOptions("model", modelArray, "KEY", "VALUE"), which add the returned array to the model select component.

Conclusion
I hope you learned how AJAX could create a better user experience on your site. I covered passing complex objects, using innerHTML to modify the view layer after it has been rendered, drawing dynamic content, manipulating tables, and using related select options. AJAX is extremely fast, secure, and allows for advanced functionality that synchronous HTML does not.

© 2008 SYS-CON Media Inc.