AJAX – What’s the buzz? Introduction and Workshop

Yesterday we had a workshop titled: Ajax, What’s the buzz? During this workshop, we discussed AJAX – Asynchronous JavaScript and XML, notable examples of Ajax implementations, the repercussions Ajax can have for the application we develop, challenges we will face when adopting Ajax and of course ways to implement Ajax. During the hands-on session, we implemented the Ajax equivalent of HelloWorld, implemented cross-domain Ajax-requests and used the RICO framework for creating an Accordion effect (Outlook style). We also implemented client-side server based validation and a tooltip/suggestion like feature.

The driving forces behind Ajax and most of the appications, next to the obvious JavaScript and the XmlHttpRequest object, are the (DHTML) ability to directly write to the DOM. For some of us, this was a first introduction to the node manipulation features in DHTML as well as the innerHtml property that we can so easily use with container elements like DIV and TD.

You can find the presentation for this workshop here: AjaxWhatsTheBuzz_30maart2006.ppt Note that the slides contain some Dutch words. Also note that the slides have hyperlinks, some of them to websites on the internet – those will function – some of them to demos that you will not have. Those same demonstrations can be found later in this article. Also see Installment 2 – more in depth examples and discussions.

AJAX - What's the buzz? Introduction and Workshop notAJAX

....

Introduction to AJAX

Of course thousands of articles have been written about AJAX ever since the term was coined in February 2005, inspired by what Google Labs had published with the Google Suggest feature. Long before the term AJAX was thought up, applications were using AJAX mechanisms. At AMIS – quite a while before my time – people like Erwin, Ate, Ton, Hans and Leon had implemented AJAX like features in the JAA and CBE applications (early 2000s). In 1998/1999 I had implemented (I)FRAME based AJAX in the Oracle Designer Web Assistant. However, AJAX really has taken off early 2005.

 

In the presentation, we discussed a number of well known examples of AJAX:

(note: you clicik on these images to go to the examples themselves)

AJAX - What's the buzz? Introduction and Workshop AJAXSuggest

AJAX - What's the buzz? Introduction and Workshop

 

AJAX - What's the buzz? Introduction and Workshop

AJAX - What's the buzz? Introduction and Workshop

AJAX - What's the buzz? Introduction and Workshop

 

Each of these examples make use of the Ajax design pattern: asynchronous communication (behind the scenes, without apparent interruption of the application for the user) followed by dynamic updates of the document in the browser (DOM manpipulation aka DHTML).
AJAX - What's the buzz? Introduction and Workshop

AJAX can be seen as the standards based way of creating RIAs (Rich Internet Applications), as opposed to proprietary technology or very poorly supported standards-to-be such as Flash (Flex, OpenLaszlo), XUL, XAML and HTC, XAMJ, XForms and even Java Applets. AJAX is supported in standard browsers (IE 5.0+, Mozilla 1.0+, Safari 1.2+- available since 1999, 2002 and 2004) using standard technologies like HTML, JavaScript, DOM manipulation through JavaScript and CSS. FRAME based Ajax has been available in far older browsers at least since 1997.

AJAX: without, old style and modern

Let’s take a brief look at a situation where Ajax may improve a Web Application. We have a web page where an Employee can be selected. Let’s assume that we have a collection of thousands of Employees, distributed over dozens of departments. In our interface, we can select a Department from a Select List as well as an Employee from another List. (in the demo that follows, we have only 25 employees but general idea is the same of course).

AJAX - What's the buzz? Introduction and Workshop

There are several ways of implementing this situation. These incluse:

1. Load all employees when the page is loaded and include all of them in the Employee Select List. Go to LoadAllIntoSelect to inspect this approach. It should be clear that this approach, while simple to implement, has two major drawbacks: loading the page can take quite long as all employees are loaded; only after all have been loaded will the hourglass disappear and will the user have control over the application. Furthermore, the user must try to find the employee he wants to select in a list that contains all of them. First selecting a Department has no (filtering) effect on the list of employees

2. Load all employees when the page is loaded into a JavaScript array and populate the Employee List in client side JavaScript code every time the Department selection changes. See LoadAllAndFilterClientSide to see this implementation. This implementation still suffers from a long load time – the user has to wait for all employees to be downloaded to the browser. However, this time the list of employees is filtered by the selected Department. This means that we now have a much shorter list to pick the employee from.

We have implemented this with an array of Employee objects that are populated during the loading of the page:

var empstore = new Array();

function Employee(deptno, empno, ename){
this.deptno=deptno;
this.empno=empno;
this.ename=ename;
}

empstore.push( new Employee('10', '1','Tom Bomer'));
empstore.push( new Employee('10', '2','Ramses Shaffy'));
...

The DepartmentList has an onChange event defined: onChange=”populateEmpForDept(this.value);” . The function that is invoked here looks like this:

function populateEmpForDept(deptno) {
   var empList = document.deptempform.emp;
   empList.options.length = 0;
   for(i=0;i<empstore.length;i++) {
     if (empstore[i].deptno == deptno) {
	empList.options[empList.options.length] 
             = new Option(empstore[i].ename, empstore[i].empno);
     }//if
   }//for
   empList.disabled=false;
}//populateEmpForDept

3. Refresh page when the Department selection changes and rebuild with the proper list of Employees. This solution is seen here: ChooseDeptThenSubmit. This implementation offers two improvements over the first listed here: the page can load fast a
s no employees are initially loaded at all and the u
ser will be able to select employees from a short list, with only the employees in the selected department. However, now we will have a full page refresh every time the department selection changes. The form is submitted from the onchange event: onChange=”document.location.href=’ChooseEmpDept’+document.deptempform.dept.value+’.html’;”. It is then up to the webserver to dynamically recreate the page with only the employees for the selected department. Note that we have simulated this with five different static html documents with each a subset of the employees. While this seems a good approach, there is still the annoying full page refresh whenever the department selection changes.

4. AJAX old style – using IFRAMES. Here we discuss an approach that is programmatic, asynchronous and basically almost everything that the hyped-up AJAX is. And it has been around since 1998 at least. It uses a (hidden) (I)FRAME to asynchronously communicatie with the server. The results of this background communication can be used to update the main document. And example of this AJAX-old-style can be seen ‘live’ here: ChooseDeptRefreshEmpIframeBasedAjax.

 

AJAX - What's the buzz? Introduction and Workshop

 

When the Department is selected, the onChange event fires. At that point, a hidden IFRAME is refreshed and a static document is loaded. For each department, a different document is loaded into the IFRAME. When the IFRAME has completed loading the document, a JavaScript function in the parent window – the main document – is invoked and the employee data is handed over:

The IFRAME is refreshed whenever the Department selection changes:

<select size="5" name="dept" onChange="retrieveEmps(this.value);">

function retrieveEmps(deptno) {
top.frames[‘getemps’].location.href = ‘dept’+deptno+’.html’;
}

The department specific documents that are loaded in the IFRAME each look like:

var empstore = new Array();

function Employee(deptno, empno, ename){
this.deptno=deptno;
this.empno=empno;
this.ename=ename;
}

empstore.push( new Employee('10', '1','Tom Bomer'));
empstore.push( new Employee('10', '2','Ramses Shaffy'));
empstore.push( new Employee('10', '3','George W. Bush'));
empstore.push( new Employee('10', '4','Muahmmed Ali'));
empstore.push( new Employee('10', '5','Anna Vink'));
empstore.push( new Employee('10', '6','Pepper Kreunen'));

function callParent() {
  window.parent.populateEmpList( empstore);
} //callParent  


</script>
  </head>
  <body onload="callParent()">
  </body>
</html>

In this example, they are static. Typically of course they would be dynamically generated by a JSP, ASP.NET, Perl, PHP etc. program.

The populateEmpList function that is called from the IFRAME is the same as before:

function populateEmpList( empstore) {
   var empList = document.deptempform.emp;
   empList.options.length = 0;
   for(i=0;i<empstore.length;i++) {
     empList.options[empList.options.length] = new Option(empstore[i].ename, empstore[i].empno);
   }//for
   empList.disabled=false;
}//populateEmpList

This IFRAME based implementation of the AJAX design pattern has a number of benefits: Broad browser support, Even in very old browsers; Fewer issues with cross domain resources (the IFRAME can load its resource from any URL, not just resources on the same domain the main document was loaded from); Support for file upload (when the IFRAME is submitted, it can upload a file, something modern AJAX does not support). IFRAME based AJAX is used in Oracle UIX and ADF Faces, exactly because of these benefits.

However, there are some drawbacks: The document to be loaded in the IFRAME needs to be aware of the context – Loaded page must invoke a JavaScript function in the parent. Only the IFRAME’s onLoad can tell when the document is loaded. Furthermore, browser security restrictions raise some barriers over accessing contents in the IFRAME from the parent document. This means we cannot load ‘dumb’ content like plain text files, XML documents etc. in the IFRAME, whatever we load has to be our own stuff that knows how to tell the parent window it is loaded. For our very own applications that may not be such an issue – even though it means every resource loaded AJAX style needs to have a piece of JavaScript – but it certainly limits our ability to access non-application resources. Smaller disadvantages are that IFRAME based Ajax is not what the Ajax hype is all about. Books, tools, frameworks and code libraries do not address nor support this type of Ajax. And we could argue that it is less elegant than what we dupe ‘real’ AJAX.
5. AJAX new style – using the XmlHttpRequest object At last we have arrived by the hype: AJAX new style, fully programmatic and using the XmlHtppRequest object. For a live demonstration, see ChooseDeptRefreshEmpModernAjax.
AJAX - What's the buzz? Introduction and Workshop

Modern AJAX uses the programmatic XmlHttpRequest object to communicate with web servers. In our example, when the Department Selection changes, the onChange event executes:

<select size="5" name="dept" onChange="loadEmployees(this.value);">

 

The function loadEmployees that is invoked will submit an Ajax request – asynchronously and invisible to the user – that will retrieve an XML document with the Employee-data for the selected department.

   var xmlHttpRequest;
  
   /**
   * Load the Employee data in the select object
   */
  function loadEmployees(deptno) {
    var file = "empsInDept"+ deptno+".xml"
    // create the object, careful to the MSFT/Other method
    if (window.XMLHttpRequest) {
      xmlHttpRequest = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) {
      xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
    }

    // executing the request, passing the targetted object
    xmlHttpRequest.onreadystatechange = processRequestChange;
    xmlHttpRequest.open("GET", file, true);
    xmlHttpRequest.send(null);
  }//loadEmployees


  /**
   * Handle the events of the XMLHttpRequest Object
   */
  function processRequestChange()  {
    if (xmlHttpRequest.readyState == 4) {
      if(xmlHttpRequest.status == 200) {
           copyEmployeeData();
      }
       else {
         alert("Error loading pagen"+ xmlHttpRequest.status +":"+ xmlHttpRequest.statusText);
      }
    }
  }

Note that in this example we use static XML documents per department; a real application would make use of dynamic server side components that would generate the XML content based on the department selection:

<EMP>
 <ROW>
  <EMPNO>20</EMPNO>
  <ENAME>Tante Trix</ENAME>
  <DEPTNO>40</DEPTNO>
 </ROW>
 <ROW>
  <EMPNO>19</EMPNO>
  <ENAME>Jeffrey Wammes</ENAME>
  <DEPTNO>40</DEPTNO>
 </ROW>
 </EMP>

When the request-cycle is complete and the response has been received, the processRequestChange function calls the copyEmployeeData() function. This function reads the responseXML property
from t
he xmlHttpRequest object. This property contains the XML document that was received as response to the AJAX request. The XML Document is examined – the collection of all ROW nodes is retrieved. Each ROW represents an Employee. Next we create entries in the Employees Select list for each Employee in the XML Document:

/**
   * Populate the list with the data from the request
   * (Could be done in a generic manner depending of the XML...)
   */
  function copyEmployeeData() {
    var list = document.deptempform.emp;
    list.disabled = false;
    var items = xmlHttpRequest.responseXML.getElementsByTagName("ROW");
    clearList(list);
    if (items.length > 0) {
      for (var i=0; i<items.length; i++) {
        var node = items[i];
        var empno = node.getElementsByTagName("EMPNO")[0].firstChild.nodeValue;
        var ename = node.getElementsByTagName("ENAME")[0].firstChild.nodeValue;
        addElementToList(list, empno, ename  );
      }// for
    }// if
    else {
     list.disabled='true';
     alert("No Employee for this department");
    }
  }// copyEmployeeData
  /**
   * remove the content of te list
   */
  function clearList(list)
  {
    while (list.length > 0)  {
      list.remove(0);
    }
  }

  /**
   * Add a new element to a selection list
   */
  function addElementToList(list, value, label)
  {
    var option = document.createElement("option");
    option.value = value;
    var labelNode = document.createTextNode(label);
    option.appendChild(labelNode   );
    list.appendChild(option);
  }

This example is but brief introduction to AJAX Modern Style. In a subsequent article, we will discuss the more advanced labs we worked on in this workshop. These include parallel Ajax requests, cross domain Ajax requests, repetitive (polling) requests and different ways of processing the AJAX request response.

6 Comments

  1. Lucas Jellema April 18, 2006
  2. Len April 15, 2006
  3. Lucas Jellema April 3, 2006
  4. Waldo Smeets April 2, 2006
  5. Lucas Jellema April 2, 2006
  6. Waldo Smeets April 2, 2006