AJAX bit by byte – Part I

AJAX (Asynchronous JavaScript and XML) was very well dealt with in the earlier articles written by Mr. G.B Shah and Mr. Ramdas himself. This article would carry over from where they had left.

I have split this article into two parts, the first part deals with the basics with a simple example which illustrates a commercially (un)used feature by websites (This explains the “bit” part in the heading) and the second part delves into more deeper concepts constructing the same example in a more robust manner with more features (the “Byte’” part).

Consider this scenario, you want to become a new user in a website which offers you email service, so you sign up for it, by filling a new user form with all the mundane details viz new user ID, password, address etc and finally after the (hectic) job is over ,you happily click the submit button … 

“This ID is already chosen by someone, please choose another ID” –This is one of numerous frustrating experiences almost every one of us must have been through and if your connection is slow then it’s even more frustrating to be kept waiting for duplicate ID selection.
This is an example of a Traditional approach where an input (in form of a HTML form) is posted to a web server and a fresh new page is generated after processing. 

The new page which is built by the server is almost similar to that of the earlier page with some addition/modification of some links. This consumes resources and bandwidth, and keeps the user waiting for some output from the server.

Within the course of this article we would design a simple new user sign up form, which would give an immediate feedback to the user with no page refresh, when a duplicate ID is found.



AJAX a new approach: 

The different approach taken by AJAX is that it forms a layer (which is present in form of JavaScript functions) between the server and the client. So Http requests to the server is actually not initiated by the HTML page, but rather it is passed to the intermediary AJAX layer which initiates, processes and finally requests the server. This layer also modifies the HTML page (DOM really) according to the response from the server without a page refresh.

This has a big advantage – consider this example, suppose you have two select (list) boxes in an organization’s website, the first one contains a list of cities while the second one contains a list which is populated dynamically according to the selection made in the first list box(say.. list of offices in the selected city). What happens usually is that the whole HTML form/page is passed to the server which process and updates the second list box dynamically. Sounds good?

But this results in a whole page refresh, and the user is kept waiting, though only for less time .But why would you send the whole page, when you actually require sending just the selected list box value. What is the need to rebuild the same page and waste bandwidth and time?

This is an example of a synchronous request where the user waits for the server response. The ‘A’ in AJAX stands for Asynchronous; this tells the browser to catch the response from server with an event. This asynchronous behavior lets the JavaScript code (AJAX layer), to carry on with its work without waiting for the response from server and thus eliminates a page refresh.

This AJAX layer sends small chunks of data (in our case just the first list box selected value) to the server and after getting the response (usually in XML) 
modifies the DOM by only rebuilding the part that needs to be changed (the second list box values) .

So how does the AJAX layer accomplishes this – As I have already mentioned the AJAX layer is nothing buta JavaScript program which uses an object known as the XMLHttpRequest object. 

JavaScript can make HTTP calls to the server using this object, and as DOM is easily accessible by JavaScript so response from server can be easily dealt with.

OK now we know the basics, let’s get into some serious stuff here. 



XMLHttpRequest Object:

We need to make Http requests to the server via JavaScript, for that we need some instance of a class that has this functionality. Microsoft had released this class in IE 5 browser as an ActiveX object on 1998 and called it XMLHTTP. After realizing the potential of this object many browsers followed suit and released their own native version of this object and called this XMLHttpRequest object.

Let’s create an instance of this class:

var xmlhttp=new ActiveXObject("Msxml2.XMLHTTP");

This declaration creates an instance of the class for newer versions of IE.
Due to browser conflicts regarding this object, you have to deal with browser compatibility issues. 

There may be some users who use older versions of IE or others browsers like Safari, mozilla, konqueror etc. If some browser doesn’t support this object you have to make the application die gracefully or make use of the traditional approach. The following code illustrates this.

CODE 1 

function getXMLHTTPobj() 
{
  var xmlhttp=null;
try {
 xmlhttp=new ActiveXObject("Msxml2.XMLHTTP"); // newer versions of windows IE
  } 
catch (e) 


try { 
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); // older versions of IE
  } 
catch (E) { 
xmlhttp=false; 
}
  }

If (!xmlhttp && typeof XMLHttpRequest!='undefined') { xmlhttp=new XMLHttpRequest(); // other browsers with XMLHttpRequest object support 

return xmlhttp; 
}


The following code is almost self explanatory; this function basically creates an XMLHTTP object and returns it to the calling function. First it tries to create the XMLHTTP instance for newer versions of IE and throws an exception if it fails to create. This exception is caught and the same process is repeated for older versions of IE and ultimately if nothing materializes then it tries to create an XMLHttpRequest object for other browsers.

Note this code is still not full proof as it will throw exception if the client uses a browser which does not support even XMLHttpRequest like Opera 7 and below, Microsoft Internet Explorer 4.0 and below and browsers made before 1997. So rectify this by using the following code instead of the last if statement code. You could use precompiled directives @cc_on for making it even more robust.

Properties of XMLHttpRequest Object:

Now that we have initialized the object now let’s use it do something useful. This object has some properties which have been mentioned in earlier article by G.B Shah, so I would only list out the important properties that are used extensively. For a detailed info about the properties you can refer 
http://www.w3schools.com/xml/xml_http.asp

1. open (method, uri, [async, [user, [password]]])
2. send ([data]) 


The open () method is used to initialize a new request. The method parameter can be GET, POST, HEAD etc; the uri parameter refers to the destination URL/File where the request should go while the last 3 options are optional.
The async parameters determine whether the request is synchronous (false) or asynchronous (true).By default it is true and it should be true for AJAX calls.

xmlhttp.open ('GET','user.xml',true);

Note: that the uri parameter has some security concerns regarding 3rd party domains.

The send () method has only one parameter which can be any data you want to send to the server. Typically POST method uses send method to send URL parameters. I would elaborate this in the second part of the article. The following code sends the request which has been configured, to use the GET method.

xmlhttp.send(null);

We have sent the request, but we still have to get the server response.

Remember that request is asynchronous i.e. the JavaScript code should not wait for the server response , this means that after the JavaScript function has completed executing its code ,it will terminate and the control will return to the webpage. So the user can keep working on the application while the server is processing the request. 

While the server does so, the readystate of the request changes (state of the request). We catch this readystate change with an event which fires whenever the readystate changes. 

The XMLHttpRequest object has a property called the onreadystatechange which allows you to specify a callback method (the portion of code which the server refers while processing). 
In Javascript, functions can be assigned to variables and object properties, we use this feature in the following code - 

CODE 3

function init_request() 

var xmlhttp=null; 
xmlhttp=getXMLHTTPobj();

xmlhttp.open(‘GET’,’user1.xml’,true); 
xmlhttp.onreadystatechange=function () // actually this is callback 

if(xmlhttp.readyState==4) 
   { 
      if (xmlhttp.status == 200) 
        { 
            var status=search(document.frm.user.value,xmlhttp); 
             if(status) update (); 
          } 
   } 

xmlhttp.send(null); 
}

The above function init_request () creates and XMLHttpRequest object by calling getXMLHTTPobj () function (see CODE 1). Then it configures the request to get the content of the user1.xml file which resides in the same directory and finally it specifies an un-named function as a callback which acts as an handler so that the server can refer back to it every time state of the request is changed.

The readystates values are described below-



Note that there are other names for the readystates like 1 for loading, 3 for receiving and so on but they mean the same thing.
In the CODE 3, by testing whether the ready state value is 4 (Complete), we have made sure that the server has completed the request and we can use the server response. 

Now comes the next part, suppose the server doesn’t find the URL requested (status code 404) or any other error, so there would no useful response hence we have to make sure that the desired error-free response is obtained. For this we check for the status property to be 200.The full list of the HTTP status codes can be obtained from http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6
We have declared a variable named ‘status’ which stores the value true/false returned by the JavaScript search () function. The search () function as you can see below takes the value of the login id text box and the xmlhttp object as parameters.

CODE 4         

                 function search(str, xmlhttp)

                    {
                           var list=xmlhttp.responseXML.getElementsByTagName('data');

                               for(var i=0;i<list.length;i++)

                                 {

                                     if(list.item(i).text == str)

                                       return true;

                                  }

                      return false;

                   }

The XMLHTTPRequest object holds the response from the server. The response in form of text resides in the responseText property and in form of XML DOM resides in the responseXML property.

The responseXML property gives us an XMLDocument object from the server response (i.e. the contents of user1.xml) .This object is in form of a DOM tree and can be easily accessed by the getElementsByTagName () which uses a tag name as argument and returns a list of elements that match the argument. In our case, tags matching ‘data’ are retrieved from the server response. 

Note: 

1. responseXML is a read-only property 2. If you use ‘*’ as the argument in the getElementsByTagName (), then list of all elements are returned.
The search () function searches for a match by storing the list of the matched elements in a list and iterating through the list. If any element in the list matches with the value in the login-id textbox, true is returned.

Let’s see the user1.xml file that has been referred many times.

CODE 5  

                         <?xml version="1.0" encoding="UTF-8" ?>

                                  <login>
                                      <data>gaurav</data> 
                                      <data>archita</data>   
                                      <data>deepak</data>   
                                      <data>subhasish</data>       
                                      <data>anudweipayan</data>     
                               </login>

user1.xml

For a return value of true, an update () function is called that to give an instant feedback to the user that this value is already taken and the submit button is disabled as you can see in the screenshot of the application.



Before going to the update function let’s see the HTML code – 

HTML CODE  LISTING
<HTML>
           <HEAD>  
                  
<TITLE> AJAX DEMO </TITLE> 
                  <link rel="stylesheet" href="testcss.css" type="text/css" />
                   <SCRIPT LANGUAGE="JavaScript" src="utils.js"></SCRIPT>
         </HEAD>
         <BODY>
                 <Label class="intro">Sign Up Form</Label>  <br> 
               <HR>
            <FORM METHOD=POST ACTION="” name ="frm">  
                     
<label> Login : </label> 
                      <INPUT TYPE="text" NAME="user" onBlur=
init_request()' onFocus='clear_text()' 
                      <div id="errormessage"></div> <br> <!—Placeholder for Updating the message on duplicate ID -->
                      <label>Email : </label> 
                      <INPUT TYPE="text" NAME="email" > <br>
                      <label>New Password </label> 
                      <INPUT TYPE="password" maxlength=11 size =21 NAME="text">
                       <HR>
                       
 <INPUT TYPE="button" name ="Submit" value="Submit" class="greenbutton">
             </FORM>
     </BODY>
</HTML>

Index.html
Whenever the user has finished typing the login name in the user text box, he should be informed if the login name is already taken by someone. For this we should query the server whenever the user textbox loses focus.
The above HTML code just calls the init_request () method whenever the login textbox loses focus. The onBlur=‘init_request ()' handles this. 
Now back to function update () – it just updates the HTML page with a message “Sorry login name is already present” whenever true is returned by the search () method.
CODE 6      

           function update()
     {

      document.getElementById("errormessage").innerHTML="sorry login name already present"; 

     document.getElementById("Submit").disabled=true;

     }

    Update ()

The getElementById (“errormessage”) searches the HTML DOM document, for an id called “errrormessage” and updates it with the message using innerHTML property; we have defined this id in our HTML page- 

<div id="errormessage"></div>

Apart from innerHTML you could use other DOM methods, but I personally feel it is lot faster. Finally we have disabled the submit button so that the user cannot submit if the user id is already present.

Ok, now we are almost done, suppose the user enters “gaurav” and gets the duplicate user-id present message, he/she proceeds with another name say “gaurav123”, now we should clear the existing error message, so whenever the user id text box gains focus we need to clear the message – this is done by 

onFocus='clear_text ()' 

The clear_text () function is shown below – 

CODE 7    

                                function clear_text()
                         {
                              document.getElementById("errormessage").innerHTML="";
                               document.getElementById("Submit").disabled=false;
                           }

    Lastly to beautify the content and positioning, CSS is used. 

CODE 8

                            

 body                    { font-family: verdana;}

#errormessage     {  position:absolute; margin-left: 20px;  display:inline; color: green; font-size:medium; }

                              /* to format display for the the "login id already present" message */

input                      { font-size: medium; }

h2,hr                      {    background-color : #efe ;border-top :4px solid #7c7 ;    color : #050 ;  }

 label                      {       font-size:medium;      color: #3399cc  ;              color : #050 ;                        }

 .greenbutton       {  background-color:#cec;  color:#black;  border:2px outset #cec;  }

   testcss.css

Pack the JavaScript functions in a file and name it as utils.js, put the CSS, HTML files in same directory in web server and test this example.

AJAX STATS 

Tests carried out suggest that AJAX saved 61% of bandwidth in comparison to a traditional approach. To view the detailed test results refer to the below mentioned link.

http://www.webperformanceinc.com/library/reports/AjaxBandwidth/index.html


Another test gave startling savings in bandwidth, time and cost. See for yourself 

http://www.developer.com/xml/article.php/3554271

    CONS OF THIS EXAMPLE: 

I have tried to use AJAX in as simple way as possible with this article, but this example is not reusable enough and runs into some browser caching issues (check Temporary Internet file folder for user1.xml).

Wouldn’t it be better if we could actually submit the login name so that it is stored in user1.xml file with no page refresh? 
In the next article we will use servlets and JDOM parser to update the xml file when the user submits the form, add a ZIP code feature (see main screenshot), see the use of POST method to prevent browser caching along with some advanced features of AJAX and finally get a look into JSON.

**** **** *****

About Author : 
I have been working at TATA Consultancy Services Ltd TCS, for the past seven months as a web developer on J2EE after completing my B.E on 2005 at ITER, Bhubaneshwar.

Mail: gaurav_devdutt@yahoo.co.in 
gaurav.devdutt@tcs.com (Please use this id for official purpose only)




Added on August 13, 2007 Comment

Comments

Post a comment

Your name:

Comment: