Welcome!

Anatole Tartakovsky

Subscribe to Anatole Tartakovsky: eMailAlertsEmail Alerts
Get Anatole Tartakovsky via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: RIA Developer's Journal, Java EE Journal, AJAX World RIA Conference

RIA & Ajax: Article

Intelligent Web Applications with AJAX

A peek into modern technologies for browser-based applications

Browser-based applications are widely used and we like the fact that we can access them from anywhere. But from the users' perspective, the productivity level of Web applications still doesn't approximate the productivity of desktop programs. The good news is the gap is closing: the accumulated potential of multiple technologies has boosted a whole new breed of HTML-based apps that are as powerful as the desktop ones. Meet AJAX.

What Is AJAX?
The name stands for Asynchronous JavaScript + XMLHTTPRequest and means you can establish socket communication between browser-based JavaScript and the server. AJAX isn't a new technology. It's a successful branding of possibilities implanted in several technologies available in modern browsers. All AJAX applications deliver a rich UI via extensive JavaScript manipulation of the HTML Document Object Model based on the precision-pointed data retrieval via XMLHttpRequest. Typical examples of AJAX applications are Google Maps and Google Suggest from Google Labs (http://labs.google.com). These applications actively monitor user input and provide real-time page updates. Most importantly, this happens without a page refresh while the user navigates through the map or types a search string.

In fact, the technologies behind these wonders have been around for a while, although they require sophisticated skills in using browser-specific tricks. Proprietary offerings with similar capabilities - Macromedia Flash plug-in, Java Applets or .NET runtime - have been available for quite some time too. The idea of integrating a scriptable transport component talking to the server into the browser was pioneered by IE 5.0. Then Firefox and other popular browsers joined the club of browsers in supporting XMLHTTPRequest as a built-in object. With cross-browser availability, these technologies gained visibility and in March of 2004 a company called Adaptive Path introduced AJAX.

In short, backing from Google and having the right browser technologies available out-of-the-box tipped the scale: these days everyone is adding client-side technologies to Web applications for a "better user experience."

AJAX vs. Classical Applications
A classic Web application model is literally a triumph of form over substance: users are forced to submit forms in exchange for pages. That said, the form submission and page delivery aren't guaranteed: worse case the user clicks again though some pages specifically warn against that. It's quite different with AJAX, where the data travels across the wire instead of entire HTML pages. This data exchange is scripted via a specific browser object - XMLHttpRequest; the appropriate logic handles the outcome of each data request, the specifc region of the page is updated instead of the entire page. The results are more speed, less traffic, and better control of information delivery.

Traditional "click-refresh" Web applications force users to interrupt the work process while waiting for the page to reload. With AJAX, a client-side script can asynchronously talk to the server while the user keeps entering data. Besides being transparent to the user, such asynchrony means more time for the server to process the request.

Classic Web applications delegate all processing to the server and force the server to manage the state. AJAX allows flexible partitioning of the application logic and state management between the client and the server. This eliminates a "click-refresh" dependancy and provides better server scalability. When the state is stored on the client-side you don't have to maintain sessions across the servers or save/expire state: the lifespan is defined by client.

AJAX: Distributed MVC
Although AJAX applications rely on JavaScript for the presentation layer, the processing power and knowledge base remain on the server. For that matter, AJAX applications talk heavily to J2EE servers, feeding data to and from Web Services and servlets. The difference between J2EE applications with an AJAX-based presentation tier and standard J2EE application is that in the first case MVC is distributed over the wire. With AJAX, View is local, while Model and Controller are distributed giving the developer the flexibility to decide which components will be client-based. Specifically, a local View renders graphics by manipulating with HTML DOM; the controller handles user input locally and at the developer's discretion extends the processing to the server via HTTP requests (Web Services, XML/RPC or others); the remote part of the Model is downloaded as needed to the client achieving in-place real-time updates of the client page; and state is collected on the client.

In future AJAX articles we'll talk about each of these components in depth and provide examples of how they came to play together. Now, without further ado, let's dive into a simple AJAX example.

Zip Codes Validation and Lookup
We'll create an HTML page containing three INPUT fields: Zip, City, and State. We'll make sure that as soon as the user enters the first three digits of the zip code, the state will get populated with the first matching state value. Once the user types in all five zip digits, we'll instantly determine and populate the appropriate city. If the zip code isn't valid (not found in the server's database), we'll turn the zip's border color to red. Such visual clues are helpful to users and have become standard in modern browsers (as an example, Firefox finds matching words in an HTML page by highlighting them in the browser search field while you type).

Let's start with a simple HTML containing three input fields: zip, city, and state. Please note that the method zipChanged() is called as soon as a character is entered in the zip field. In turn, the JavaScript function zipChanged() (see below) calls the function updateState() when the zip length is three and up-dateCity() when the length of the zip is five. Both updateCity() and updateState() delegate most of the work to another function - ask().

Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()" style="width:60"/>
City: <input id="city" disabled maxlength="32" style="width:160"/>
State:<input id="state" disabled maxlength="2" style="width:30"/>

<script src="xmlhttp.js"></script>
<script>
var zipField = null;
function zipChanged(){
    zipField = document.getElementById("zipcode")
    var zip = zipField.value;
    zip.length == 3?updateState(zip):zip.length == 5?updateCity(zip):"";

}
function updateState(zip) {
    var stateField = document.getElementById("state");
    ask("resolveZip.jsp?lookupType=state&zip="+zip, stateField, zipField);
}
function updateCity(zip) {
    var cityField = document.getElementById("city");
    ask("resolveZip.jsp? lookupType=city&zip="+zip, cityField, zipField);
}
</script>

The function ask() communicates with the server and assigns a callback to process the server's response (see the following code). Later, we'll look at the content of the dual-natured resolveZip.jsp that looks up the city or state information depending on the number of characters in the zip field. Importantly, ask() uses the asynchronous flavor of the XmlHttpRequest so that populating the state and city fields or coloring the zip border is done without slowing data entry down. First, we call request.open(), which opens the socket channel with the server using one of the HTTP verbs (GET or POST) as the first argument and the URL of the data provider as a second one. The last argument of the request.open() is set to true, which indicates the asynchronous nature of the request. Note that the request hasn't been submitted yet. That happens with the request.send() call, which can provide any necessary payload for POST. With asynchronous requests we have to assign the request's callback using the request.onreadystatechanged attribute. (If the request had been synchronous, we could have processed the results immediately after request.send, but we would have blocked the user until the request was completed.)

HTTPRequest = function () {
   var xmlhttp=null;
   try {
     xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   } catch (_e) {
     try {
       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
     } catch (_E) { }
   }
   if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
     try {
       xmlhttp = new XMLHttpRequest();
     } catch (e) {
       xmlhttp = false;
   } }
   return xmlhttp;
}

function ask(url, fieldToFill, lookupField) {
    var http = new HTTPRequest();
    http.open("GET", url, true);
    http.onreadystatechange = function (){ handleHttpResponse(http, fieldToFill, lookupField)};
    http.send(null);
}

function handleHttpResponse(http, fieldToFill, lookupField) {
   if (http.readyState == 4) {
     result = http.responseText;
     if ( -1 != result.search("null") ) {
       lookupField.style.borderColor = "red";
       fieldToFill.value = "";
     } else {
       lookupField.style.borderColor = "";
       fieldToFill.value = result;
} } }

The HttpRequest() function (see above) used by ask() is a cross-browser constructor of an instance of the XMLHTTPRequest; we'll look at it a bit later. For now, note how the invocation of handleResponse() is wrapped by an anonymous function (a so-called closure) function (){ handleHttpResponse(http, fieldToFill, lookupField)}.

The code for that function is dynamically created and compiled every time we do an assignment to the http.onreadstatechange property. As a result, JavaScript creates a pointer to the context with all variables that the enclosing method - ask() - has access to. It's done so the anonymous function and handleResponse() are guaranteed full access to all context-hosted variables until the reference to the anonymous function is garbage-collected. In other words, whenever our anonymous function gets invoked, it can refer to the request, fieldToFill, and lookupField variables as seamlessly as if they were global. It's also true that every invocation of ask() will create a separate copy of the environment with the variables holding the values of the moment the closure was formed.


More Stories By Victor Rasputnis

Dr. Victor Rasputnis is a Managing Principal of Farata Systems. He's responsible for providing architectural design, implementation management and mentoring to companies migrating to XML Internet technologies. He holds a PhD in computer science from the Moscow Institute of Robotics. You can reach him at vrasputnis@faratasystems.com

More Stories By Anatole Tartakovsky

Anatole Tartakovsky is a Managing Principal of Farata Systems. He's responsible for creation of frameworks and reusable components. Anatole authored number of books and articles on AJAX, XML, Internet and client-server technologies. He holds an MS in mathematics. You can reach him at atartakovsky@faratasystems.com

More Stories By Igor Nys

Igor Nys is a Director of Technology Solutions at EPAM Systems, Inc, a company combining IT consulting expertise with advanced onshore-offshore software development practices. Igor has been working on many different computer platforms and languages including Java, C++, PowerBuilder, Lisp, Assembler since the mid 80's. Igor is currently managing a number of large distributed projects between US and Europe. In addition Igor is the author of the award-winning freeware system-management tools, and he was closely involved in the development of XMLSP technology - one of the AJAX pioneers.

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Bill Watkins 11/09/06 12:18:37 PM EST

www.ajaxmaker.com:8080/blog/zipsearch.htm.
volumn1 issue 1 The above link is non functional to the public. Bad form for any magazine.

Overall nice first effort though.

Dennis 10/17/06 08:39:39 AM EDT

The text and the code are not consistent. This makes it tough to follow the concepts being presented in the article. For example: "Let's look at the function handleResponse()..." There is no function "handleResponse()" in the code. The function ask() is explained before its presented in the code examples. The anonymous function "handleHTTPRequest" is presented in the text as "function (){ handleHttpResponse(http, fieldToFill, lookupField)}" and in the code as "function handleHttpResponse(http, fieldToFill, lookupField)".
Educational articles should be consistent to maximize their value.