I am sure you already heard about AJAX, the "new" way of building Web
application where using HTML, Javascript, DOM, and XML you can
build very interactive Web applications, some examples of
this interactivity are Google (suggest, local, mail), MSN, Amazon, .....
If the term Ajax is
relatively new, the technologies used are quite old now. And you do not
need anything new to be able to leverage this approach in your current
development, and since it is mainly a client (browser) based technology
this can be used whether you develop your application in Java, PHP, or
or even PL/SQL for the Web. In the same time, you do not want to have
to develop too much of the client side to handle user interaction, this
is where new frameworks that provide support of this technologies,
let's say AJAX based, are very interesting. It is now possible to
create very interactive Web application without passing 80% of your
time in the client side development - that could be generated from your
server obviously.
In the same time, before adopting such framework, it is important to
understand what is happening. This is why I am creating this quick
introduction based on 2 simple use cases:
- loading message:
you often want to provide some
feedback to your user when your browser is processing some data
- dependent lists:
how you can easily create dependent lists, in lot of application you
want to drive a selection list from another
Update May 30:
If you have tested my sample on Safari, you can see that the first request works, but following subsequent requests do not, on work around is to modify the HTTP header adding the following value, has to be done before the send, just send a old date...
httpRequest.setRequestHeader('If-Modified-Since','Sun,3 Jun 1973 00:00:00 GMT');
What do you need to know?
The first interesting part is the object XMLHttpRequest. This object is
currently supported by most of the browsers. As usual with HTML and
Javascript the cross browser/platform testing is one of the most
important part of your project. XMLHttpRequest is not new since
Microsoft has implemented it in Internet Explorer 5 as an ActiveX
object. Also it has been later on integrate as a native component into
Mozzila and Netscape (7.0), and into Apple Safari. If originally this
object as been created to load data, as XML in the
background, you can using it to load any data.
Creating XMLHttpRequest Object
As usual with Javascript, it begins with interoperability issue ;-),
since in the MSFT world the XMLHttpRequest is implemented as an ActiveX
and in the other world(s) it is an native object, you have different
ways to create the object. The idea is too test if the current browser
supports or not the object and depending of the result create the
object.
if
(window.ActiveXObject)
{
//
Microsoft Way
httpRequest = new
ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest)
{
// Others...
httpRequest = new XMLHttpRequest();
}
Note: another way of choosing which code path to use depending of the
version of the browser is to use
conditional compilation
for the Javascript engine.
Also I would add that it is probably good to provide a degraded version
of your application if you can not control which browser will be used
by your client, or if you want to provide that to mobile people. This
is for example what Google Mail is doing with its
Basic HTML
view.
Retrieving the data
asynchronously
One of the most interesting features of the XMLHttpRequestObject is the
fact that you get data from a URL in the background of the user
activity. This is how you can give lot of interactivity to your
applications.
httpRequest.open("GET",
"./getEmployeeList?deptno=10", true);
httpRequest.onreadystatechange= function () {processRequest(); }
;
httpRequest.send(null);
The
open
method sets the different values that will be used by your request,
such as the type of request, the URL, if it is synchronous or not.
The "magic" comes from the
onreadystatechange property.
This propery set an handler that will be called when the property
readyState
changes, when the request is sent, loading, or completed... Meaning,
this is in this event handler, the
processRequest
method in the sample, that you test if the response has been completed
correctly, and process the data.
Note: even if it is possible, I do not think that you should use the
XMLHttpRequest in a synchronous mode since it will freeze the browser
of the user, for the duration of the request.
Processing the response
As I said above the magic happens in the event handler associated with
the state of the request. Let's see how you manipulate the request and
response:
function
processRequest()
{
if (httpRequest.readyState == 4)
{
if(httpRequest.status == 200)
{
// process data as XML
httpRequest.responseXML;
// or Text
alert(httpRequest.responseText);
}
else
{
alert("Error loading page\n"+
httpRequest.status
+":"+ httpRequest.statusText);
}
}
}
The
readyState
propery is used to know if all the data of the response have been
received or not, the different value for the state are:
- 0 : uninitialized
- 1 : loading
- 2 :loaded
- 3 : interactive
- 4 : completed
Most of the time, you will just test the status 4. In my example I wait
for status==4 and then I check the status of the response. The
status
is the status returned by the server, for example 200 for OK, 404 for
not found.
Then you can treat the response as XML using the
responseXML,
in this case you can manipulate the XML using the client DOM API. But
you can also directly take the content as a string using the
responseText
property.
Manipulating the Data
You now have the data back from the request, as Text or XML, you just
need using Javascript manipulate them and copy then into some part of
your page. So all is based on the client side. Let's do a very simple
example before moving to the use cases:
What
is happening?
Since I have explained the call above, here is the simple code that is
used to copy the content from the XMLHttpRequest object to the page:
.....
if(httpRequest.status == 200)
{
var contentViewer =
document.getElementById("contentViewer");
contentViewer.innerHTML =
httpRequest.responseText;
}
....
Most of the time, if you do not use XML you just have to copy
the content of the result into a section of your page, so to do it you
use:
- create a DIV tag in your
page with a specific id. (or other...)
- get the object you want to
copy into using the document.getElementById()
method, that is the most simple way...
- then from the object just
use the innerHTML
property that represent the content of this DIV object. (You can also
use the DOM API, to do the same thing, I am sure puris will say that
this is the only way to do it correctly... )
In most of the frameworks the data are exchanged in XML and some
generic methods are calls on the client side to propulate data in the
different components of the page.
Usecase
1: Loading Message
One common use case is to be able to have some feedback during
processing of a request. Using the same approach you can print a
message until the response is completely done.
What
is happening?
The tip here is just to take a zone where you want to print the status
("Loading..." for example). When the XMLHttpRequest status is different
than 4 (completed) just print the status in this section
using for example the innerHTML property. When the request is
completed, just move the content of this zone to blank, or in our case
the result of the request is printed into it.
....
if
(httpRequest.readyState == 4)
{
if(httpRequest.status == 200)
{
// print the content of the page
var contentViewer = document.getElementById("contentViewer");
contentViewer.innerHTML = httpRequest.responseText;
}
}
else
{
// Print the loading message....
var contentViewer = document.getElementById("contentViewer");
contentViewer.innerHTML = "<b
style='color:red;'>Loading....<b>";
}
...
Usecase
2: Dependent Lists
In lot of applications, you have submission form when one drop down
list is controlled by another one. You have several way to support that
depending of the size of your data set. For example you can download
all the records (master and detail) and use some client side
programming to refresh the content of the detail list depending of the
value selected in the master one; or another solution is to
just reload the page.
Using XMLHttpRequest, you can now just call the server to populate the
values of the detail list when the user select another value in the
master list. (and you can implement a client side cache if you want to
avoid a second call with the same parameters, but this is another
story...)
What
is happening?
Nothing more complex than in the previous examples, on the
onChange
of the master list (dept in the example) , you call a Javascript method
that create the XMLHttRequest, with the correct parameter.
Then in the event handler of this request, you populate the data as XML
and add them to the detail list (emp in the example).
In this specific example I used XML, but if you want for simpler code
you can write all in HTML and use the innerHTML property, but this is
just a choice of implementation isn't?
Summary
First of all, you have seen that what we have behind AJAX is not just
new technologies. The technologies exists now for a while, they have
been exposed to the masse by Google, MSN, and other Web sites. The term
itself is definitevely a recent one...
Also, I have showed you simple examples that can help you for your
current developments, but you need to write some code on the client.
The real future of AJAX, is when this is bundle into a framework, into
the Faces components your are using. So before starting to implement
such code in your application you should take a look around to see if
any solution exists that can answer your need...
You can download the source of the demonstrations
here. I tried to keep the code as simple as possible by providing all the source in each single html file.