Sei sulla pagina 1di 126

The term AJAX is a pseudo-acronym for "Asynchronous JavaScript And XML," but is

now used much more broadly to cover all methods of communicating with a server using
JavaScript. As we will see, Ajax is not always asynchronous and does not always involve
XML.

The Purpose of Ajax


The main purpose of Ajax is to provide a simple and standard means for a web page to
communicate with the server without a complete page refresh. To illustrate this, consider
a simple registration form. You have very likely experienced the frustration of having to
try multiple usernames when registering for some new website. You fill out the entire
form, hit the submit button, wait for a second or so, and then get the same form right back
with a message saying that the username you have chosen is not available. You try
another easy-to-remember username and find it is also not available. You repeat this
several times until finally you pick some obscure username. This process wouldn't be
nearly as bad if you didn't have to wait for the entire page to refresh each time you tried a
new username.

But that's a very simple example. Some web-based applications require constant
interaction with a database through a middle-tier. Take, for example, an interface for
updating employee records. The traditional way of doing this is illustrated below.
Traditional Web Application

1. First, the application shows a list of employees to pick from.


(AjaxBasics/Demos/EmployeeAdmin.jsp)
2. When the user chooses an employee, the server returns a new page (FIRST
REFRESH) and a form is displayed. (AjaxBasics/Demos/EditEmployee.jsp)

3. The user can then edit the employee data (e.g, change "Andrew" to "Andy") and
submit the form. The server then returns the new page (SECOND REFRESH).
(AjaxBasics/Demos/EditEmployee.jsp)

4. To get back to the employee list to begin the process of modifying another
employee's data, the user would have to click on the "Employee List" link
(THIRD REFRESH).

An Ajax Web Application

Ajax makes this process much simpler for the user. Records, and even individual fields of
a record, can be edited one at a time without full page refreshes. This method is
illustrated below.
1. Like with the traditional method, the Ajax application shows a list of employees
to pick from. (AjaxBasics/Solutions/EmployeeAdmin.html)

2. When the user chooses an employee, the page doesn't reload. Instead, an Ajax call
to the server is made, the server returns the HTML form and JavaScript is used to
display the form on the page.

3. The user can then edit the form fields. Each time a changed form field loses focus
the change is sent to the server with Ajax, the server-side code updates the data in
the database and sends back the updated list of employees to the browser.
JavaScript is again used to display the updated list on the page.

4. The employee list is updated to reflect the changes made. Notice "Andrew" has
been changed to "Andy" in the list. A message is displayed letting the user know
that the database was updated.

All this is accomplished without having to do even one complete refresh. This is the
major benefit of Ajax.

The XMLHttpRequest Object


The mechanism for sending data to and retrieving data from the server with Ajax is the
XMLHttpRequest object. Unfortunately, modern browsers that support XMLHttp
requests have different methods for doing so. We'll examine the Mozilla method and the
Internet Explorer method and then we'll abstract both methods with a single user-defined
function.

Creating an XMLHttpRequest Object


Mozilla Method

The Mozilla method is the most straightforward of the two. It uses a simple
XMLHttpRequest() constructor to create the object.
Code Sample: AjaxBasics/Demos/CreateXMLHttpRequest-
moz.html
<html>
<head>
<title>XMLHttpRequest in Mozilla</title>
<script type="text/javascript">
function Start()
{
try
{
xmlhttp = new XMLHttpRequest();
document.getElementById("Content").innerHTML="<h1>Using
XMLHttpRequest Object</h1>";
}
catch (e)
{
document.getElementById("Content").innerHTML="<h1>XMLHttp cannot be
created!</h1>";
}
}
</script>
</head>
<body>
<a href="javascript:Start()">Start</a>
<div id="Content"></div>
</body>
</html>
Code Explanation

This code attempts to create an XMLHttpRequest object using the XMLHttpRequest()


constructor. If it succeeds, it writes out "Using XMLHttpRequest Object" to the body of
the page. If it fails, it writes out "XMLHttp cannot be created!"

Internet Explorer Method

Microsoft Internet Explorer uses an ActiveX control to implement an XMLHttpRequest


object. New and improved versions of this control have been released over time, so our
code should check for the latest version available on the user's machine and use that one.

Code Sample: AjaxBasics/Demos/CreateXMLHttpRequest-


ie.html
<html>
<head>
<title>XMLHttpRequest in Internet Explorer</title>
<script type="text/javascript">
function Start()
{
var ieXmlHttpVersions = new Array();
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.7.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.6.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.5.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.4.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.3.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "Microsoft.XMLHttp";

var i;
for (i=0; i < ieXmlHttpVersions.length; i++)
{
try
{
var xmlhttp = new ActiveXObject(ieXmlHttpVersions[i]);
document.getElementById("Content").innerHTML="<h1>Using " +
ieXmlHttpVersions[i] + "</h1>";
break;
}
catch (exc)
{
alert(ieXmlHttpVersions[i] + " not supported.");
}
}

if (typeof xmlhttp == "undefined")


document.getElementById("Content").innerHTML="<h1>XMLHttp cannot be
created!</h1>";
}
</script>
</head>
<body>
<a href="javascript:Start()">Start</a>
<div id="Content"></div>
</body>
</html>
Code Explanation

This code creates an array containing the names of all the different versions of
Microsoft's XMLHttp ActiveX control, starting with the most recent. It then loops
through the array and uses the first available control to create an xmlhttp object. As soon
as it finds one, it writes out the version being used to the body of the page. If none of the
versions is supported, it writes out "XMLHttp cannot be created!"

Cross-browser XMLHttpRequest Creation

The following code sample combines the previous two in one function that handles
XMLHttpRequest creation in both browsers. It first tries the Mozilla method as it's much
more likely that Internet Explorer will eventually adopt this method than it is that Mozilla
and other browsers will support ActiveX controls.

Code Sample: AjaxBasics/Demos/CreateXMLHttpRequest.html


---- Code Omitted ----
<script type="text/javascript">
function Start()
{
try
{
var xmlhttp = new XMLHttpRequest();
document.getElementById("Content").innerHTML="<h1>Using
XMLHttpRequest Object</h1>";
}
catch(err1)
{
var ieXmlHttpVersions = new Array();
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.7.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.6.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.5.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.4.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.3.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "Microsoft.XMLHttp";

var i;
for (i=0; i < ieXmlHttpVersions.length; i++)
{
try
{
var xmlhttp = new ActiveXObject(ieXmlHttpVersions[i]);
document.getElementById("Content").innerHTML="<h1>Using " +
ieXmlHttpVersions[i] + "</h1>";
break;
}
catch (err2)
{
alert(ieXmlHttpVersions[i] + " not supported.");
}
}
}

if (typeof xmlhttp == "undefined")


document.getElementById("Content").innerHTML="<h1>XMLHttp cannot be
created!</h1>";
}
</script>
---- Code Omitted ----

Using an XMLHttpRequest Object

So, now that we have an XMLHttpRequest object created, what do we do with it? We use
it to make HTTP requests. To do so, we initialize the object with the open() method,
which takes three arguments.

XMLHttpRequest open() Method Arguments


Method Description
Request Type String. Usually POST, GET, or HEAD
URL String. The URL receiving the request.
Boolean. Whether the request should be made asynchronously (true) or
Asynchronous
synchronously (false).
A typical open() method call is shown below.

xmlhttp.open("GET","Demo.xml",true);

Request Types

Although the HTTP specification identifies several methods of HTTP requests , the most
commonly supported (and used) methods are GET, POST and HEAD.

HEAD

The HEAD method is the least commonly used of the three; however, for simple
requests, it can be all you need. It simply returns the meta-information contained in the
HTTP headers. The call would look like this:

xmlhttp.open("HEAD","Demo.jsp",true);

And the response might look like this:

Server: Microsoft-IIS/5.1
X-Powered-By: ASP.NET
Date: Fri, 03 Mar 2006 17:47:47 GMT
Content-Type: text/xml
Accept-Ranges: bytes
Last-Modified: Fri, 03 Mar 2006 14:07:51 GMT
ETag: "50c59dccb3ec61:99e"
Content-Length: 21

The XMLHttpRequest request is sent as follows:

xmlhttp.send(null);

We'll explain why null is passed in just a moment.

GET

The GET method is used to send information to the server as part of the URL. The server
returns the same header information that the HEAD method returns, but it also returns the
body of the message (i.e, the content of the page). Any name-value pairs to be processed
by the receiving page should be passed along the querystring. The call would look like
this:

xmlhttp.open("GET","Demo.jsp?FirstName=Nat&LastName=Dunn",true);

The response would be the same as the response shown for the HEAD method followed
by the message body, which would typically be plain text, HTML or XML.

Again, the XMLHttpRequest request is sent as follows:


xmlhttp.send(null);

POST

The POST method is used to send information as an enclosed entity. The call would look
like this:

xmlhttp.open("POST","Demo.jsp",true);

The response header is somewhat different in that it specifies that the returned content is
not cacheable. Like with GET, the message body would typically be plain text, HTML or
XML.

The XMLHttpRequest request is sent as follows:

xmlhttp.setRequestHeader("Content-Type","application/x-www-form-
urlencoded;");
xmlhttp.send("FirstName=Nat&LastName=Dunn");

As you can see, with POST, we first need to set the content type to "application/x-www-
form-urlencoded;". This tells the server to expect form data. In the send method, we
include name-value pairs. These name-value pairs are available to the receiving page for
processing.

Nothing can be sent in this manner with the HEAD and GET methods, which is why null
was passed in the previous examples.

We'll see later that we can also send data in other formats, such as raw XML, using the
POST method.

Asynchronous vs. Synchronous Requests

The asynchronous argument should almost always be set to true. After all, that's the "A"
in Ajax. Synchronous calls force the browser to wait for a response from the server
before continuing. This leaves the user unable to interact with the browser until the
response is complete. Asynchronous requests allow the browser to continue to process
code while waiting for a response.

Handling the Response

When using asynchronous calls, we cannot be sure when the response will come, so we
must write code that waits for the response and handles it when it arrives. We do this with
a callback function. Callback functions are functions that are triggered by some event. In
our case, the event we are looking for is a change in the state of the xmlhttp response.
This event is captured by the xmlhttp object's onreadystatechange property. We can
assign a callback function to this property like this:
xmlhttp.onreadystatechange=function()
{
//Do something here
}

The xmlhttp object's readyState property holds the current state of the response. There are
five possible states (0-4), which are described below.

Values of the readyState Property


State Description
0 uninitialized
1 loading
2 loaded
3 interactive
4 complete

This use of an inline function may be new to you. In JavaScript, functions are first-class
objects and can be assigned to variables or properties of other objects. We could also
create a named function and assign that function to xmlhttp.onreadystatechange.

The following sample file illustrates how the readystatechange event is handled.

Code Sample: AjaxBasics/Demos/ReadyStateChange.html


---- Code Omitted ----
function Start()
{
---- Code Omitted ----
var ContentDiv = document.getElementById("Content");
if (typeof xmlhttp == "undefined")
{
ContentDiv.innerHTML = "<h1>XMLHttp cannot be created!</h1>";
}
else
{
xmlhttp.open("HEAD", "Demo.xml", true);
xmlhttp.onreadystatechange=function()
{
ContentDiv.innerHTML += "Ready State: " + xmlhttp.readyState +
"<br/>";
}
xmlhttp.send(null);
}
}
---- Code Omitted ----

Code Explanation
The output will look something like this. The actual ready states returned will depend on

your setup.

In practice, before doing anything with the xmlhttp response data, we want to make sure
the readyState is complete (4), so we put a condition inside our function to check for this:

xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
//Do something here
}
}

Now we're ready to do something with the data returned. Before looking at an example,
let's take a look at the properties and methods of the xmlhttp object, so we know what's
available to us.

XMLHttpRequest Object Properties


Property Description
Specifies the callback function to be triggered when the ready state
onreadystatechange
changes.
readyState Holds the state of the response.
responseText Holds the message body as a string.
responseXML Holds the message body as an XML object.
Holds the status code returned from the server (e.g, 200 for success,
status
404 for page not found, etc.).
statusText Holds the status text returned from the server.
XMLHttpRequest Object Methods
Method Description
abort() Aborts the xmlhttp request.
getAllResponseHeaders() Retrieves the values of all the HTTP headers as a string.
Retrieves the value of the specified HTTP header as a
getResponseHeader(header)
string.
open(Method,URL,Async) Initializes the XMLHttpRequest object.
send(header) Sends the HTTP request to the server.
setRequestHeader(header,value) Specifies the name and value of an HTTP header.

A common application is to check the status property to make sure that the request was
successful and then to output the message body to a div on the HTML page. The
following sample file demonstrates this.

Code Sample: AjaxBasics/Demos/UsingXMLHttpRequest-


Get.html
---- Code Omitted ----
else
{
xmlhttp.open("GET", "Demo.jsp?FirstName=Nat&LastName=Dunn", true);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
ContentDiv.innerHTML=xmlhttp.responseText;
}
}
xmlhttp.send(null);
}
---- Code Omitted ----

Code Explanation

This page simply "copies" the response text (xmlhttp.responseText) and "pastes" it into
the "Content" div on the page.

Ajax Basics Conclusion


In this lesson of the Ajax tutorial, you have learned the purpose of Ajax and the basic
foundation for creating Ajax applications.

To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

The Purpose of Frameworks


JavaScript frameworks can serve several purposes:

• Abstraction. Writing JavaScript is notoriously difficult in large part because of the


browser and platform differences. Although this has improved a lot since the
Netscape 4 / IE 4 days, JavaScript developers still have to be aware of differences
in browser object models. One purpose of frameworks is to abstract those
differences.
• Widget Libraries. Many frameworks provide libraries of pre-written,
customizable widgets (expandable trees, accordions, autocompletes, drag-and-
drop controls, etc.).
• Development Structure. Some frameworks make it easier to create structured,
object-oriented Ajax applications.

Choosing a Framework

Choosing a framework to use for your Ajax applications is a difficult task. At the time of
this writing, the AjaxPatterns website (http://ajaxpatterns.org/Ajax_Frameworks) listed:

• 30 multi-purpose Ajax frameworks


• 32 Java-specific Ajax frameworks
• 27 PHP-specific Ajax frameworks
• 15 .NET-specific Ajax frameworks

Many of these frameworks are created by individuals or small groups and most are non-
commercial. So how do you choose? It's a tough job, but here are some general
guidelines.

1. Choose a framework with staying power. The more mature frameworks like
Prototype and Dojo, which we will review shortly, have built up pretty large
followings, so they are more likely to persist. They are also more likely to be
better documented and supported by an online community.
2. Choose a framework that is either language neutral or specific to your server-side
language. This is pretty obvious, but you don't want a PHP framework if you are
building a Java application.
3. Choose a framework that plays nicely with other frameworks. For example,
script.aculo.us and Rico both require Prototype, so if you want to use some of
their cool dynamic features, you will have to use Prototype as well.
4. Choose a framework that fits your skillset. If your developers are very
comfortable with JavaScript, you might choose a framework that is JavaScript-
centric like Prototype or Dojo. If you are a team of Java or JSP developers who
have not done much client-side programming, you might choose a framework like
AjaxAnywhere , which autogenerates the JavaScript. Such frameworks provide
less flexibility but may decrease development time.
We will look at two popular frameworks: Dojo and Prototype. Note that these
frameworks have a much broader focus than Ajax, but for now, we'll be focusing on how
they handle XMLHttpRequests.

Dojo
Dojo is a multi-purpose JavaScript toolkit that, according to its website, "makes
professional web development better, easier, and faster." Dojo has been in development
since late 2004 and is one of the most comprehensive JavaScript toolkits available. It is
client-side specific so it can be used on any platform with any server-side language. The
documentation for Dojo is relatively good compared with other frameworks.

Downloading Dojo

The latest version of Dojo is freely available for download at http://dojotoolkit.org as a


zip file. Simply unzip the files to a folder on your webserver. For our Ajax examples, you
will only need the dojo.js library, which is included with your class files
(AjaxFrameworks/Demos/Dojo/dojo.js).

Using Dojo for Ajax

To make the Dojo library available, include the dojo.js file as you would any other
JavaScript library:

<script language="javascript" src="dojo.js"></script>

Dojo uses an object-oriented approach with dojo being the top-level object. Ajax
applications use the input/output APIs, which are included with this line of code:

dojo.require("dojo.io.*");

XMLHttpRequests are made using the bind() method, which takes one parameter: a
request object, which has the following properties and methods :

Request Object Properties


Property Description
url String. The location of the resource being requested.
String. Mimetype used to interpret the contents of the response with.
mimetype Defaults to "text/plain". It is used to determine whether the response text
should be evaluated with the JavaScript eval() function.
method String. Method of request. Usually "get" or "post". Defaults to "get".
Object. A key/value mapping of properties to be constructed into parameters
content passed with the data request. For example, querystring parameters or form
fields in POST requests.
transport String. Explicitly specifies the transport object to use for the request. It
Request Object Properties
Property Description
defaults to "XMLHttp". Other options are "IFrame I/O" and "ScriptSrcIO".
Boolean. Defaults to false. Determines whether or not the request should be
changeUrl
made "bookmarkable".
DOM Node that specifies a form to be serialized and submitted by this
formNode
request.
Boolean. Defaults to false. Determines whether the accepting transport
sync
should attempt to make the request synchronously.
Boolean. Defaults to false. Indicates whether or not this Request was
bindSuccess
accepted and dispatched by any transport.
Boolean. Defaults to false. Indicates whether the result of the Request should
useCache be cached and whether requesting a result for this Request from the cache is
acceptable.
Request Object Methods
Property Description
Callback method used when load, error or another status-specific handler
handle(type,
is not defined or not available. The event type may be determined via
data, event)
string comparision with the type parameter (e.g, if (type == "load") {...)
Callback method used when data is successfully returned for this Request.
The type parameter will always be "load". The data parameter passes in
the data returned from the server, subject to any pre-processing the
load(type,
accepting transport class may have applied. For example, if a mimetype of
data, event)
"text/javascript" is specified then the result will be passed through
JavaScript's eval() function. For XMLHttpRequests, the event parameter is
a reference to the XMLHTTP object used to dispatch the network request.
Callback method used when data cannot be returned for this Request. The
error(type,
type parameter will always be "load". The errorObject parameter provides
errorObject)
details about the failure.
abort() Method for aborting pending Request dispatch.

Here is the syntax of a simple call to the bind() method:

Syntax
dojo.io.bind(
{
url: URL,
load: CallBackFunction,
method: "get", //or "post"
content: {
param1: value,
param2: value,
param3: value
}
});
The code sample below shows how we would change part of our EmployeeAdmin.html
document to use Dojo.

Code Sample:
AjaxFrameworks/Demos/Dojo/EmployeeAdmin.html
<html>
<head>
<title>Employee Administration</title>
<link rel="stylesheet" type="text/css" href="../Styles/Main.css">
<script type="text/javascript"
src="http://o.aolcdn.com/dojo/0.4.3/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.io.*");
var OutputDiv;
function GetEmployeeList(URL)
{
OutputDiv = document.getElementById("EmployeeList");
OutputDiv.innerHTML="<h2>Loading...</h2>";

dojo.io.bind(
{
url: URL,
load: Display,
method: "post"
});
}

function Display(TYPE, DATA, REQ)


{
OutputDiv.style.display="block";
if (DATA.indexOf("Failed") != -1)
{
OutputDiv.className="Warning";
OutputDiv.innerHTML=DATA;
}
else
{
OutputDiv.innerHTML = DATA;
}
}

window.onload = function()
{
GetEmployeeList("../EmployeeList.jsp");
}
</script>
</head>
---- Code Omitted ----

Code Explanation

As you can see, we only need to make use of the url and method properties and the load
method of the Request object that is passed to the bind() method. To pass parameters in
with the XMLHttpRequest, we would need to include the content property as well.
Another thing to notice is that the callback function (Display()) no longer needs to check
the status and the readyState of the xmlhttp object. This is handled by Dojo.

Prototype
Prototype is a multi-purpose JavaScript toolkit that, according to its website, "aims to
ease development of dynamic web applications." Many other libraries, such as
script.aculo.us and Rico are built on top of Prototype and the Ruby on Rails framework
has built-in support for Prototype. These tie-ins make it likely that Prototype will be
around for a long time. Like Dojo, it is client-side specific so it can be used on any
platform with any server-side language. There is no good documentation on the Prototype
site, but Sergio Pereira has put together some very good online documentation at
http://www.sergiopereira.com/articles/prototype.js.html. Webucator has created a PDF
version hosted at http://www.sergiopereira.com/articles/DeveloperNotes-Prototype-
JS.pdf.

Downloading Prototype

The latest version of Prototype is freely available for download at


http://prototype.conio.net as a .js file. Rename the file to "prototype.js" and save it in a
folder on your webserver. We have included a copy of it with your class files
(AjaxFrameworks/Demos/Prototype/prototype.js).

Using Prototype for Ajax

To make the Prototype library available, include the prototype.js file as you would any
other JavaScript library:

<script language="javascript" src="prototype.js"></script>

XMLHttpRequests are made using the Ajax.Request() class, which, when instantiated,
takes two parameters: a URL string and an object, which has the following properties and
methods:

Ajax.Request() 2nd Parameter Properties


Property Description
method String. Method of request. Usually "get" or "post".
String. Querystring parameters or form fields in POST requests, using the
parameters
querystring syntax (e.g, "firstname=Nat&lastname=Dunn")
Boolean. Defaults to true. Determines whether the request should be made
asynchronous
synchronously.
Ajax.Request 2nd Parameter Methods
Property Description
onComplete(xmlhttp) Callback method used when onSuccess or onFailure is not defined
Ajax.Request 2nd Parameter Methods
Property Description
or not available. The only parameter is a reference to the
XMLHTTP object used to dispatch the request.
Callback method used when data is successfully returned for this
onSuccess(xmlhttp) Request. The only parameter is a reference to the XMLHTTP
object used to dispatch the request.
Callback method used when data cannot be returned for this
onFailure(xmlhttp) Request. The only parameter is a reference to the XMLHTTP
object used to dispatch the request.

Here is the syntax of a simple call to the Ajax.Request() constructor:

Syntax
new Ajax.Request(URL,
{
method: "get", //or "post"
onComplete: CallBackFunction,
parameters: "param1=value&param2=value&param3=value"
});

The code sample below shows how we would change part of our EmployeeAdmin.html
document to use Prototype.

Code Sample:
AjaxFrameworks/Demos/Prototype/EmployeeAdmin.html
<html>
<head>
<title>Employee Administration</title>
<link rel="stylesheet" type="text/css" href="../Styles/Main.css">
<script type="text/javascript" src="../../../prototype.js"></script>
<script type="text/javascript" src="../Scripts/Effects.js"></script>
<script type="text/javascript">
var OutputDiv;
function GetEmployeeList(URL)
{
OutputDiv = document.getElementById("EmployeeList");
OutputDiv.innerHTML="<h2>Loading...</h2>";

new Ajax.Request(URL,
{
method: "post",
onComplete: Display
});
}

function Display(REQ)
{
OutputDiv.style.display="block";
if (REQ.responseText.indexOf("Failed") != -1)
{
OutputDiv.className="Warning";
OutputDiv.innerHTML=REQ.responseText;
}
else
{
OutputDiv.innerHTML = REQ.responseText;
}
}

window.onload = function()
{
GetEmployeeList("../EmployeeList.jsp");
}
</script>
</head>
---- Code Omitted ----

Code Explanation

As you can see, we only need to make use of the url property and the second parameter's
method property and the onComplete method. To pass parameters in with the
XMLHttpRequest, we would need to include the parameters property as well.

Like with Dojo, the callback function (Display()) no longer needs to check the status and
the readyState of the xmlhttp object as Prototype takes care of this behind the scenes.

Throughout the rest of this manual, we will be using Prototype to handle our
XMLHttpRequests.

Other Popular Frameworks


Direct Web Remoting (DWR)

DWR is one of the more popular Java-specific frameworks. It makes it possible to call
Java methods directly from JavaScript by blackboxing the data transfer to and from the
server to make it feel to the developer as if Java objects were natively available to the
browser.

AjaxAnywhere

According to its website, "AjaxAnywhere is designed to turn any set of existing JSP or
JSF components into AJAX-aware components without complex JavaScript coding." The
major benefit of AjaxAnywhere is that it makes it possible to create Ajax applications
without writing much JavaScript. The downside is that it does not provide as much
flexibility as the more JavaScript-centric solutions.
Simple Ajax (SAJAX)

Like DWR, Sajax allows you to access server-side code directly from JavaScript. It
supports ASP, ColdFusion, Perl, PHP, Python, and Ruby, but not Java.

Sarissa

Sarissa is a JavaScript-centric library that isn't specific to any server-side language. It


provides a simple function that emulates Mozilla's XMLHttpRequest for Internet
Explorer, but that's about it when it comes to client-server communication. It does make
using XSLT in the browser very easy.

Other Frameworks

As noted in the beginning of this lesson, there are many more frameworks. For a good
list, see http://ajaxpatterns.org/Ajax_Frameworks.

Ajax Frameworks Conclusion


In this lesson of the Ajax tutorial, you have learned about some common Ajax
frameworks and how to use a couple of the most popular to handle XMLHttpRequests.

To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

The HTML Document Object Model


In this lesson of the Ajax tutorial, you will learn...

1. To work with the HTML DOM.


2. To access specific nodes.
3. To access nodes by class name.
4. To remove a node.
5. To create a new node.
6. To dynamically create an HTML page.
7. To modify node styles.
8. To modify node classes.
9. To add events to nodes.

The HTML Document Object Model (DOM) is a W3C standard that defines a set
of HTML objects and their methods and properties. JavaScript can be used to create and
destroy these objects, to invoke their methods, and to manipulate their properties.
If you have done any JavaScript programming on the web then you have almost
definitely worked with the HTML DOM. A subset of the object hierarchy is shown

below.

This course assumes that you have some experience working with the DOM. This lesson
is concerned with identifying and manipulating document nodes with the purpose of
repainting a page with JavaScript. For now, we will be using data generated on the client.
Later, we'll see how to repaint a page using data returned from the server.

Accessing Nodes
There are many types of nodes in an HTML document, but the three that you most often
need to work with are element nodes, attribute nodes, and text nodes.

Accessing Element Nodes

Element nodes can be accessed by their tag name, id, or position within the HTML
document hierarchy.

getElementsByTagName()

The getElementsByTagName() method of an element node retrieves all descendant


elements of the specified tag name and stores them in a NodeList, which is exposed by
JavaScript as an array. The following example illustrates how getElementsByTagName()
works.

Code Sample: HTMLDOM/Demos/getElementsByTagName.html


<html>
<head>
<script type="text/javascript">
function getElements()
{
var elems = document.getElementsByTagName("li");
var msg="";
for (var i=0; i < elems.length; i++)
{
msg += elems[i].innerHTML + "\n";
}
alert(msg);
}
</script>
<title>getElementsByTagName()</title>
</head>

<body onload="getElements();">
<h1>Rockbands</h1>
<h2>Beatles</h2>
<ol>
<li>Paul</li>
<li>John</li>
<li>George</li>
<li>Ringo</li>
</ol>
<h2>Rolling Stones</h2>
<ol>
<li>Mick</li>
<li>Keith</li>
<li>Charlie</li>
<li>Bill</li>
</ol>
</body>
</html>
Code Explanation

When this page loads, the following alert box will pop up:

As you can see, the method returns all the node's descendants, not just the direct children.
getElementById()

The getElementById() method of the document node returns a reference to the node with
the specified id. The following example illustrates how getElementById() works.

Code Sample: HTMLDOM/Demos/getElementById.html


<html>
<head>
<script type="text/javascript">
function getElements(PARENTNODE,TAGNAME)
{
var elems = PARENTNODE.getElementsByTagName(TAGNAME);
var msg="";
for (var i=0; i < elems.length; i++)
{
msg += elems[i].innerHTML + "\n";
}
alert(msg);
}
</script>
<title>getElementById()</title>
</head>

<body onload="getElements(document.getElementById('BeatleList'),'li');">
<h1>Rockbands</h1>
<h2>Beatles</h2>
<ol id="BeatleList">
<li>Paul</li>
<li>John</li>
<li>George</li>
<li>Ringo</li>
</ol>
<h2>Rolling Stones</h2>
<ol id="StonesList">
<li>Mick</li>
<li>Keith</li>
<li>Charlie</li>
<li>Bill</li>
</ol>
</body>
</html>
Code Explanation
When this page loads, the following alert box will pop up:

Accessing Element and Text Nodes Hierarchically

There are several node methods and properties that provide access to other nodes based
on their hierarchical relationship. The most common and best supported of these are
shown in the table below.

Properties for Accessing Element Nodes


Property Description
childNodes[] A nodeList containing all of a node's child nodes.
firstChild A reference to a node's first child node.
lastChild A reference to a node's last child node
nextSibling A reference to the next node at the same level in the document tree.
parentNode A reference to a node's parent node.
previousSibling A reference to the previous node at the same level in the document tree.

The this Object

The this keyword provides access to the current object. It references the object (or
element) that it appears in.

The following example shows a page (HTMLDOM/Demos/Hierarchy.html) on which a


mouse click on any element will pop up an alert box giving information about that
element's position in the object hierarchy.
When you click on the middle list item, for example, you get an alert that looks like this:

This shows that the list item's parent is an unordered list (UL), its first child is a text node
("List Item 2"), its last child is the same as it only has one child, its next and previous
siblings are both text nodes, and it has only one child node (the text node). The alert
above was generated in Firefox. As we'll see later, the result will be slightly different in
Internet Explorer.

Attaching Events

It is possible to attach all sorts of events, such as clicks, mouseovers, mouseouts, etc., to
elements on the page. The simplest, standard cross-browser method for adding events is
to assign an event handler property to a node. The syntax is shown below:

node.onevent = DoSomething;

In HTMLDOM/Demos/DOM.js, there is a cross-browser AttachEvent() function shown


below:

/*
Function Name: AttachEvent
Arguments: OBJ,EVT,FNCT
Action: cross browser: attaches event to passed in object. FNCT will
be the event's callback function.
Returns: true on success
*/
function AttachEvent(OBJ,EVT,FNCT)
{
if (OBJ.addEventListener)
{
OBJ.addEventListener(EVT,FNCT,true);
return true;
}
else if (OBJ.attachEvent)
{
return OBJ.attachEvent("on"+EVT,FNCT);
}
}
The addEventListener() node method is part of the DOM 2 specification. It is supported
by Mozilla, but not by Internet Explorer. Internet Explorer has its own proprietary
method, attachEvent(), which essentially works the same way. Our function above
attaches events to nodes. Throughout the course, you'll find this in the DOM.js library;
however, if you prefer to use the simple node.onevent style, in most cases it will work
just as well. However, our AttachEvent() function has a big advantage: it allows for
multiple callback functions to be attached to a single event. The following example
illustrates this.

Code Sample: HTMLDOM/Demos/Events.html


<html>
<head>
<title>Events</title>
<script type="text/javascript" src="DOM.js"></script>
<script type="text/javascript">
function SetEvents1()
{
var trigger = document.getElementById("Trigger");
trigger.onclick=sayHi;
trigger.onclick=sayBye;
}

function SetEvents2()
{
var trigger = document.getElementById("Trigger");
AttachEvent(trigger,"click",sayHi);
AttachEvent(trigger,"click",sayBye);
}

function sayHi()
{
alert("Hi!");
}

function sayBye()
{
alert("Bye!");
}
</script>
</head>
<body>
<a href="javascript:SetEvents1()">Attach events using node.onevent
syntax.</a><br/>
<a href="javascript:SetEvents2()">Attach events using AttachEvent()
function.</a>
<hr/>
<div id="Trigger" style="border:1px solid blue; cursor:pointer;">
Click to trigger events.
</div>
</body>
</html>
Code Explanation
When the page loads, the "Trigger" div has no events attached to it.

1. Click on the link that reads "Attach events using node.onevent


syntax." Then click on the "Trigger" div. A single "Bye" alert pops up.
This is because the call to sayHi() was replaced by the call to sayBye().
2. Refresh the page and then click on the link that reads "Attach
events using AttachEvent() function." Now click on the "Trigger" div
again. Both the "Hi" and "Bye" alerts pop up. The order in which they pop
up may depend on which browser you are using.

Being able to have multiple callback functions associated with a single object event can
be useful. As an example, you might have a calculation() function that is triggered when
a button is clicked. You may later want to make that same action (the click of the button)
cause another part of the page to be updated. As these are two separate tasks, you would
separate them into different functions, both of which can be tied to the same event.

Accessing Attribute Nodes

getAttribute

The getAttribute() method of an element node returns the value of the specified attribute.
According to the DOM specification, the value should be returned as a string; however,
Internet Explorer may return the attribute value as a string, number or boolean. The
syntax is shown below.

myNode.getAttribute("AttName");

attributes[]

The attributes[] property references the collection of a node's attributes. On the face of it,
such a collection could be very useful; however, the browsers handle the attributes
collection differently, making use of it a bit risky. Internet Explorer includes all possible
attributes of a node in its attributes collection, whereas Firefox includes only those
attributes currently used by the node. In practice, it's better to access attributes with the
getAttribute() method.

Accessing Nodes by Type, Name or Value


nodeType

Every node has a nodeType property, which contains an integer corresponding to a


specific type. For example, 1 is an element node, 2 is an attribute node, 3 is a text node,
etc. The W3C DOM specifies a set of constants that correspond to these integers. These
constants are properties of every node. Unfortunately, Internet Explorer's DOM doesn't
support these constants, so it's a good idea to add them to your DOM library. The
constants are listed below:
Node Type Constants
Constant Integer
ELEMENT_NODE 1
ATTRIBUTE_NODE 2
TEXT_NODE 3
CDATA_SECTION_NODE 4
ENTITY_REFERENCE_NODE 5
ENTITY_NODE 6
PROCESSING_INSTRUCTION_NODE 7
COMMENT_NODE 8
DOCUMENT_NODE 9
DOCUMENT_TYPE_NODE 10
DOCUMENT_FRAGMENT_NODE 11
NOTATION_NODE 12

To add these to a script library, simply include the following code at the top of the script:

var ELEMENT_NODE = 1;
var ATTRIBUTE_NODE = 2;
var TEXT_NODE = 3;
var CDATA_SECTION_NODE = 4;
var ENTITY_REFERENCE_NODE = 5;
var ENTITY_NODE = 6;
var PROCESSING_INSTRUCTION_NODE = 7;
var COMMENT_NODE = 8;
var DOCUMENT_NODE = 9;
var DOCUMENT_TYPE_NODE = 10;
var DOCUMENT_FRAGMENT_NODE = 11;
var NOTATION_NODE = 12;

To find all of a node's child element nodes, you would loop through its childNodes
collection checking each node one by one:

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


{
if (node.childNodes[i].nodeType==ELEMENT_NODE)
{
alert("This is an element node.");
}
}

nodeName

Every node also has a nodeName property. For elements and attributes, the nodeName
property returns the tag name and attribute name, respectively. For other node types, the
nodeName property returns a string beginning with a pound sign (#) and indicating the
node type (e.g, #text or #comment).
nodeValue

The nodeValue is usually used with text nodes and it simply returns the text value of the
node.

Accessing Nodes by Class Name

There is no built in method for getting an element's child nodes by class name, but we
can find the class of an element using its className property. The function shown in the
file below loops through all elements in a document checking each element's className.
It returns an array containing all the matched elements.

Code Sample:
HTMLDOM/Demos/getElementsByClassName.html
---- Code Omitted ----
<script type="text/javascript">
function GetElementsByClassName(CLASS,NODE)
{
var startNode = NODE || document;
var AllTags = startNode.getElementsByTagName("*");
if (AllTags.length == 0) AllTags = startNode.all; //for IE
var Elems = new Array();
var re = new RegExp("(^|\\s+)" + CLASS + "(\\s+|$)");
for (var i=0; i<AllTags.length; i++)
{
if (re.test(AllTags[i].className)) Elems[Elems.length] = AllTags[i];
}
return Elems;
}

function init()
{
var MenuOptions = GetElementsByClassName("MenuOptions");
alert(MenuOptions.length);
}
</script>
<title>Menus</title>
</head>
<body onload="init();">
<div style="position:absolute; z-index:1000; left:0px; top:0px;"
id="Menus">
<div class="Menu" id="Menu1">
<div class="MenuHead">Beatles</div>
<div class="MenuOptions">
<a href="http://www.paulmccartney.com">Paul</a>
<a href="http://www.johnlennon.com">John</a>
<a href="http://www.georgeharrison.com">George</a>
<a href="http://www.ringostarr.com">Ringo</a>
</div>
</div>
<div class="Menu" id="Menu2">
<div class="MenuHead">Rolling Stones</div>
<div class="MenuOptions">
<a href="http://www.mickjagger.com">Mick</a>
<a href="http://www.keithrichards.com">Keith</a>
</div>
</div>
</div>
---- Code Omitted ----

Code Explanation

The W3C DOM allows for passing the wildcard "*" to an element's
getElementsByTagName() method, which stores a nodeList containing all descendant
element nodes in the AllTags variable. Unfortunately, Internet Explorer doesn't support
this and will return an empty nodeList. To handle this, we set the variable AllTags to
document.all, which accomplishes the same thing in Internet Explorer.

A regular expression is created to hold a pattern that checks that the class name passed in
to the function is either at the beginning or end of the element's class name or is
surrounded by spaces. This is necessary because of the possibility of a compound class
name (e.g, class="bright important").

We then loop through AllTags storing each match in the Elems array. The function then
returns the Elems array.

Prototype's getElementsByClassName() Method

Many JavaScript frameworks have functionality for getting elements by class name.
Prototype extends the document object with a getElementsByClassName() method,
which takes two parameters: the class name and the element to search in (optional). If the
second parameter is not specified, it searches the entire document body. The following
sample does the same thing as the previous one using Prototype's
document.getElementsByClassName() method.

Code Sample:
HTMLDOM/Demos/getElementsByClassName_prototype.ht
ml
<html>
<head>
<link rel="stylesheet" type="text/css" href="Menus.css">
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">
function init()
{
var MenuOptions = document.getElementsByClassName("MenuOptions");
alert(MenuOptions.length);
}

</script>
<title>Menus</title>
</head>
<body onload="init();">
<div style="position: absolute; z-index: 1000; left: 0px; top: 0px;"
id="Menus">
<div class="Menu" id="Menu1">
<div class="MenuHead">Beatles</div>
<div class="MenuOptions">
<a href="http://www.paulmccartney.com">Paul</a>
<a href="http://www.johnlennon.com">John</a>
<a href="http://www.georgeharrison.com">George</a>
<a href="http://www.ringostarr.com">Ringo</a>
</div>
</div>
<div class="Menu" id="Menu2">
<div class="MenuHead">Rolling Stones</div>
<div class="MenuOptions">
<a href="http://www.mickjagger.com">Mick</a>
<a href="http://www.keithrichards.com">Keith</a>
</div>
</div>
</div>
<div id="divBody">Page</div>
</body>
</html>

Removing Nodes from the DOM


Element nodes have a removeChild() method, which takes a single parameter: the child
node to be removed. There is no W3C method for a node to remove itself, but the
following function will do the trick:

function RemoveElement(ELEM)
{
return ELEM.parentNode.removeChild(ELEM);
}

Sometimes it's useful to remove all of a node's children in one fell sweep. The function
below will handle this.

function RemoveAllChildren(PARENT)
{
while (PARENT.hasChildNodes())
{
PARENT.removeChild(PARENT.childNodes[0]);
}
}

Both of these functions are in our DOM.js library at HTMLDOM/Demos/DOM.js. We'll


examine some other functions in this library in a bit and we'll also add some new ones.
DOM Differences: The Whitespace Problem

The W3C specification is not entirely clear on how certain whitespace should be treated
in the DOM. The whitespace in question is any that occurs between a close tag and an
open tag (e.g, </tr> <tr>), between two open tags (e.g, <tr> <td>), or between two close
tags (e.g, </td> </tr>). The question is: should this whitespace be preserved or ignored in
the DOM. The answer, it turns out, is unclear ; however, the way a browser treats this
space is very important. To illustrate, open HTMLDOM/Demos/Hierarchy.html in
Internet Explorer and click on the middle list item. The alert that pops up is shown below:

Notice that the nextSibling and previousSibling properties both reference list item nodes,
whereas they referenced text nodes in Firefox. If you were to click on the UL element
itself, you would find that Internet Explorer considers it to have three child nodes,
whereas Firefox considers it to have seven. Firefox counts the whitespace-only text
nodes. Internet Explorer does not.

Creating New Nodes


The document node has separate methods for creating element nodes and creating text
nodes: createElement() and createTextNode(). These methods each create a node in
memory that then has to be placed somewhere in the object hierarchy. A new node can be
inserted as a child to an existing node with that node's appendChild() and insertBefore()
methods. These methods and some others are described in the table below.

Methods for Inserting Nodes


Method Description
Takes a single parameter: the node to insert, and inserts that node after the
appendChild()
last child node.
Takes two parameters: the node to insert and the child node that it should
insertBefore()
precede. The new child node is inserted before the referenced child node.
Takes two parameters: the new node and the node to be replaced. It
replaceChild()
replaces the old node with the new node and returns the old node.
Takes two parameters: the attribute name and value. If the attribute already
setAttribute()
exists, it replaces it with the new value. If it doesn't exist, it creates it.
The sample below illustrates how these methods work.

Code Sample: HTMLDOM/Demos/InsertingNodes.html


<html>
<head>
---- Code Omitted ----

<script type="text/javascript">
function AppendNewListItem()
{
var li = document.createElement("li");
var liText = document.createTextNode("New List Item");
li.appendChild(liText);
List.appendChild(li);
}

function PrependNewListItem()
{
var li = document.createElement("li");
var liText = document.createTextNode("New List Item");
li.appendChild(liText);
List.insertBefore(li,List.firstChild);
}

function ChangeStartNum()
{
var start;
if (start=List.getAttribute("start"))
start++;
else
start=2;
List.setAttribute("start",start);
}

function ReplaceOlWithUl()
{
List.parentNode.replaceChild(List2,List);
List = List2;
}

var List, List2;


function init()
{
List = document.getElementById("TheList");
List2 = document.getElementById("TheList2");
}
</script>
<title>Inserting Nodes</title>
</head>

<body onload="init()">
<div onclick="AppendNewListItem()">Append List Item</div>
<div onclick="PrependNewListItem()">Prepend List Item</div>
<div onclick="ChangeStartNum()">Change Start Number</div>
<div onclick="ReplaceOlWithUl()">Replace ordered list with bulleted
list</div>
<ol id="TheList">
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
</ol>
<ul id="TheList2">
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
<li>List Item</li>
</ul>
</body>
</html>
Code Explanation

The page is shown below in a browser. Click on any of the menu items to see the
methods in action.

A Note on the setAttribute() Method

You can use the setAttribute() method to change the value of all attributes by name as
you would expect with one exception. In Internet Explorer, the class attribute must be
referrred to as "className" in the setAttribute() method. This means that you have to
branch your code when using setAttribute() for setting the class:

var isIE = (navigator.appName == "Microsoft Internet Explorer");


if (isIE)
{
var classTerm = "className";
}
else
{
var classTerm = "class";
}
node.setAttribute(classTerm,"warning");

Rather than go through all this work, it is easier to use the className property to set the
class attribute. This will work in both browsers:

node.className = "warning";

The HTML Document Object Model


Conclusion
In this lesson of the Ajax tutorial, you have learned to work with the HTML DOM to
create and modify HTML page elements dynamically with JavaScript.

To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

Creating a DOM Document with


JavaScript
The W3C DOM specifies an implementation property of the document object. While this
property is supported by both Mozilla and Internet Explorer, its createDocument()
method, which is used to create a virtual W3C DOM Document, is not supported by
Internet Explorer 6. So, we have to branch our code. First, we'll examine the W3C
standard method for creating a DOM Document.

var XmlDoc = document.implementation.createDocument("", "", null);

The parameters have to do with namespaces and validation. For our purposes, the code
should be written exactly as shown above.

Internet Explorer, as you might guess, uses an ActiveX control to create a new DOM
Document:

var XmlDoc = new ActiveXObject("Microsoft.XMLDOM");


Both Mozilla and Internet Explorer support the non-standard load() method of the DOM
Document to load XML files. A cross-browser function for creating and populating a
DOM Document with an XML file is shown below.

function DomDoc(FILE,ASYNC)
{
var Doc;
try
{
Doc = document.implementation.createDocument("", "", null);
}
catch (exc)
{
Doc = new ActiveXObject("Microsoft.XMLDOM");
}
if (typeof ASYNC != "undefined") Doc.async=ASYNC;
Doc.load(FILE);
return Doc;
}

The value of the async property determines whether the Document can handle multiple
processes simultaneously. Setting async to false ensures that one process is complete
before another begins.

Accessing, Creating and Modifying XML


Nodes
The properties and methods we saw for accessing and inserting nodes into HTML
documents are also applicable to XML documents. They are shown again below.

Properties for Accessing Element Nodes


Property Description
childNodes[] A nodeList containing all of a node's child nodes.
firstChild A reference to a node's first child node.
lastChild A reference to a node's last child node
nextSibling A reference to the next node at the same level in the document tree.
parentNode A reference to a node's parent node.
previousSibling A reference to the previous node at the same level in the document tree.
Methods for Inserting Nodes
Method Description
Takes a single parameter: the node to insert, and inserts that node after the
appendChild()
last child node.
Takes two parameters: the node to insert and the child node that it should
insertBefore()
precede. The new child node is inserted before the referenced child node.
Takes two parameters: the new node and the node to be replaced. It
replaceChild()
replaces the old node with the new node and returns the old node.
Methods for Inserting Nodes
Method Description
Takes two parameters: the attribute name and value. If the attribute already
setAttribute()
exists, it replaces it with the new value. If it doesn't exist, it creates it.

The demo below shows how to load an XML document, to read parts of it into a string
and then output that string as HTML to a part of the page.

Code Sample: XML/Demos/XML.html


<html>
<head>
<title>XML</title>
---- Code Omitted ----

<script type="text/javascript" src="DOM.js"></script>


<script type="text/javascript">
var XmlDoc;
var NodesAsList="";

function init()
{
document.getElementById("btnLoad").disabled=false;
document.getElementById("btnDisplay").disabled=true;
document.getElementById("btnClear").disabled=true;
}

function LoadXml()
{
XmlDoc = DomDoc('Beatles.xml',false);
NodesAsList="";
document.getElementById("btnLoad").disabled=true;
document.getElementById("btnDisplay").disabled=false;
}

function DisplayNodes(DOC)
{
NodesAsList += "<ol style='font-size:smaller;'>";
for (var i=0; i < DOC.childNodes.length; i++)
{
Node=DOC.childNodes[i];
Class = (Node.nodeType==TEXT_NODE) ? "TextNode" : "NonTextNode";

NodesAsList += "<li class=" + Class + ">";


NodesAsList += Node.nodeName + ": " + Node.nodeValue;
if (Node.hasChildNodes())
{
DisplayNodes(Node);
}
NodesAsList += "</li>";
}

if(DOC.nodeType==ELEMENT_NODE)
{
for (var i=0; i < DOC.attributes.length; i++)
{
NodesAsList += "<li class='Attribute'>";
NodesAsList += DOC.attributes[i].nodeName + ": " +
DOC.attributes[i].nodeValue;
NodesAsList += "</li>";
}
}

NodesAsList += "</ol>";
document.getElementById("divXml").innerHTML = NodesAsList;
document.getElementById("btnDisplay").disabled=true;
document.getElementById("btnClear").disabled=false;
}

function ClearXml()
{
document.getElementById("divXml").innerHTML = "";
NodesAsList="";
document.getElementById("btnDisplay").disabled=false;
document.getElementById("btnClear").disabled=true;
}
</script>
</head>
<body onLoad="init();">
<form>
<input type="button" id="btnLoad" value="Load XML"
onClick="LoadXml();">
<input type="button" id="btnDisplay" value="Display XML"
onClick="DisplayNodes(XmlDoc);">
<input type="button" id="btnClear" value="Clear XML"
onClick="ClearXml();">
</form>
<div id="divXml" style="font-size:xx-large;"></div>
</body>
</html>
Code Explanation

The browser output is shown below:


1. The page loads and shows three buttons: "Load XML", "Display
XML", and "Clear XML". Only the first is enabled.
2. When the user clicks on the "Load XML" button, the DOM
Document is created and populated using the DomDoc() function we saw
earlier. Aside from the buttons, the page does not change but the new
DOM Document is available for processing.
3. The user can then click on the "Display XML" button, which
builds an HTML list as a string and assigns it to the innerHTML property
of the divXml div. The list appears on the page.
4. The user then has the option to click on the "Clear XML" button,
which simply changes the innerHTML property of the divXml div to an
empty string, thereby removing the list from the page.

Note that the DOM Document's async property is set to false to ensure that the XML
document is completely loaded before we begin reading its nodes.

Creating an AddChild() Function

Adding nodes to the DOM can be a lot of work. It can involve several steps, including:

1. Creating a new element node.


2. Appending the element node as a child of another element.
3. Creating a new text node.
4. Appending the text node to the new element node.
5. Adding one or more attributes with the setAttribute() method of the new element.

The user defined function below makes this process easier.

function AddChild(DOC, PARENT, CHILD, CHILDTEXT, ATTRIBUTES)


{
var ChildElement;
if (typeof(CHILD) == "string")
{
ChildElement = DOC.createElement(CHILD);
}
else
{
ChildElement = CHILD;
}

if (typeof CHILDTEXT != "undefined" && CHILDTEXT != null)


{
var ChildText = DOC.createTextNode(CHILDTEXT);
ChildElement.appendChild(ChildText);
}

if (typeof ATTRIBUTES != "undefined")


{
var Attributes = ATTRIBUTES;
for (Att in Attributes)
{
ChildElement.setAttribute(Att,Attributes[Att]);
}
}

PARENT.appendChild(ChildElement);
return ChildElement;
}

This AddChild() function requires the first three parameters: the DOM Document, parent-
to-be node, and child-to-be (either an existing node or the name of the node-to-be). The
function can also take the text that will become the contents of the new child and an array
of attributes for the new child. The function would be called as follows.

var NewChild = AddChild(DomDocument, ParentNode, ChildNodeOrName,


ChildText, AttributesArray);

Receiving XML Responses


As you have probably guessed, all this manipulation of XML with JavaScript would
eventually take us back to Ajax and the XMLHttpRequest object. We will start with a
script that makes a call to the web server to get data to populate an HTML table. When it
first loads, the page has a simple link that reads "Show Table". When the link is clicked,
the table shows up on the page:

The page works as follows:

1. When the user clicks on the link, JavaScript is used to make a call to
Employees.jsp on the web server.
2. The Employees.jsp page is used to make a call to the database, which returns a
recordset of all employees in the Employees table. That recordset is looped
through to create and return an XML document to the browser. The structure of
the XML document is shown below:

(The nodes for


Employees 3 through 9 are collapsed in the diagram above.)
3. As soon as the browser receives and completely loads the response, it iterates
through the Employee nodes creating an HTML table and then displays that table
on the page.

Let's take a look at the code.

Code Sample: XML/Demos/Table.html


<html>
<head>
<title>Dynamic Table</title>
<link rel="stylesheet" type="text/css" href="Table.css">
<script type="text/javascript" src="../../prototype.js"></script>
<script src="DOM.js" type="text/javascript"></script>
<script type="text/javascript">
var MainTable, TableDataSrc, RowElement, ColumnNames, ColumnWidths;

MainTable = "MainTable";
TableDataSrc = "Employees.jsp";
RowElement = "Employee";
ColumnNames = new Array("Salesperson","Title","Birth Date","Hire
Date","Extension");
ColumnWidths = new Array(24,24,21,21,8);

function GetRows()
{
new Ajax.Request(TableDataSrc,
{
method: "get",
onComplete: ShowResult
});
}

function BuildTable()
{
RemoveAllChildren(document.getElementById("HeaderRow"));
RemoveAllChildren(document.getElementById("BodyRows"));
CreateHeaderRow();
GetRows();
}

function CreateHeaderRow()
{
var HeaderRow = document.getElementById("HeaderRow");

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


{
var width=ColumnWidths[i];
var atts = new Object();
atts["width"] = width+"%";
AddChild(document, HeaderRow, "th", ColumnNames[i], atts);
}
}

function ShowResult(REQ)
{
var xmlDoc = REQ.responseXML.documentElement;
RemoveTextNodes(xmlDoc,true);

var OutputResult = document.getElementById("BodyRows");


var RowData = xmlDoc.getElementsByTagName(RowElement);
AddTableRowsFromXmlDoc(RowData,OutputResult);
document.getElementById(MainTable).style.display = "";
}

function AddTableRowsFromXmlDoc(XmlNodes,TableNode)
{
for (i=0; i<XmlNodes.length; i++)
{
var newRow = AddChild(document, TableNode, "tr");

if (i%2==0)
newRow.className = "EvenRow";
else
newRow.className = "OddRow";

for (j=0; j<XmlNodes[i].childNodes.length; j++)


{
AddChild(document, newRow, "td",
XmlNodes[i].childNodes[j].firstChild.nodeValue);
}
}
}
</script>
</head>

<body>
<a href="javascript:void(0);" onclick="BuildTable()">Show Table</a>
<div id="divBody">
<table border="1" width="780" cellpadding="2" cellspacing="0"
id="MainTable" align="center" style="display:none">
<thead>
<tr id="HeaderRow"></tr>
</thead>
<tbody id="BodyRows"></tbody>
</table>
</div>
</html>
Code Explanation

Let's walk through the code step by step in the order the page is processed.

1. As the page loads, the following variables are declared and


assigned values:
2. var MainTable, TableDataSrc, RowElement, ColumnNames,
ColumnIds, ColumnWidths;
3.
4. MainTable = "MainTable";
5. TableDataSrc = "Employees.jsp";
6. RowElement = "Employee";
7. ColumnNames = new Array("Salesperson","Title","Birth
Date","Hire Date","Extension");
ColumnWidths = new Array(24,24,21,21,8);

o MainTable holds the name of the div in which the table will
be displayed.
o TableDataSrc holds the name of the server-side script that
will return the XML content.
o RowElement holds the name of the node in the XML
document that will correspond to a single row. In this case, each
Employee node will become a single table row.
o ColumnNames and ColumnWidths hold arrays containing
values that will correspond to the table header text and table
column widths, respectively.
8. The initial HTML in the body of the page looks like this:
9. <a href="javascript:void(0);"
onclick="BuildTable()">Show Table</a>
10. <div id="divBody">
11. <table border="1" width="780" cellpadding="2"
cellspacing="0" id="MainTable" align="center">
12. <thead>
13. <tr id="HeaderRow"></tr>
14. </thead>
15. <tbody id="BodyRows"></tbody>
16. </table>
</div>

We'll use JavaScript/Ajax to populate the table header row (HeaderRow) and
table body rows (BodyRows).

17. The onclick event of the "Show Table" link calls the BuildTable()
function (shown below).
18. function BuildTable()
19. {
20. RemoveAllChildren(document.getElementById("HeaderRow"))
;
21. RemoveAllChildren(document.getElementById("BodyRows"));
22. CreateHeaderRow();
23. GetRows();
}

This function uses the RemoveAllChildren() function from our DOM.js library to
empty out the table header row and all the table body rows. It then calls
CreateHeaderRow() and GetRows(). We'll examine those next.

24. CreateHeaderRow() looks like this.


25. function CreateHeaderRow()
26. {
27. var HeaderRow = document.getElementById("HeaderRow");
28.
29. for (var i=0; i<ColumnNames.length; i++)
30. {
31. var width=ColumnWidths[i];
32. var Atts = new Array();
33. Atts["width"] = width+"%";
34. Atts["id"] = ColumnIds[i];
35. AddChild(document, HeaderRow, "th", ColumnNames[i],
Atts);
36. }
}

This function loops through the ColumnNames array and uses the AddChild()
function from our DOM.js library to insert th elements in our table header row.

37. GetRows() takes care of the call to the server using Prototype's
Ajax.Request() constructor.
38. function GetRows()
39. {
40. var ContentDiv = document.getElementById(MainTable);
41. new Ajax.Request(TableDataSrc,
42. {
43. method: "get",
44. onComplete: ShowResult
45. });
}

46. The ShowResult() function is shown below.


47. function ShowResult(REQ)
48. {
49. var xmlDoc = REQ.responseXML.documentElement;
50. RemoveTextNodes(xmlDoc,true);
51.
52. var OutputResult = document.getElementById("BodyRows");
53. var RowData = xmlDoc.getElementsByTagName(RowElement);
54. AddTableRowsFromXmlDoc(RowData,OutputResult);
55. document.getElementById(MainTable).style.display = "";
}

The first two lines of the function store the document element of the DOM
Document in the XmlDoc variable and remove all whitespace-only text nodes.
The next three lines store the table body in the OutputResult variable and the
XML nodeList in the RowData variable and pass both to the
AddTableRowsFromXmlDoc() function. The last line makes the table appear on
the page.

56. The AddTableRowsFromXmlDoc() function is shown below.


57. function AddTableRowsFromXmlDoc(XmlNodes,TableNode)
58. {
59. for (i=0; i<XmlNodes.length; i++)
60. {
61. var newRow = AddChild(document, TableNode, "tr");
62.
63. if (i%2==0)
64. newRow.className = "EvenRow";
65. else
66. newRow.className = "OddRow";
67.
68. for (j=0; j<XmlNodes[i].childNodes.length; j++)
69. {
70. AddChild(document, newRow, "td",
XmlNodes[i].childNodes[j].firstChild.nodeValue);
71. }
72. }
}

This function loops through the passed-in XML nodeList, creating a new table
row for each node in the list. It then sets the class name of the row. The inner loop
iterates through all the child nodes (e.g, Salesperson, Title, etc.) of the current
node (e.g, the current Employee), creating a table data cell for each.

XML and Ajax Conclusion


XML plays an integral role in most Ajax applications. In this lesson, you have learned to
create XML objects with JavaScript and to receive XML data from the server.
To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

Login Form
Have you ever forgotten your username or password for a website? Have you waited 10
seconds for a full page to redraw while the only thing new is a message telling you that
the username and password are not recognized. Ajax can make that process much less
painful for the user.

Imagine a simple login form like the one shown below, but on a page with a lot of other

content:

When the user fills the form out with a bad password, an error message appears and the

username is highlighted:

The rest of the page should stay the same. Ajax makes this possible without refreshing
the entire page. The code for this is shown below:

Code Sample: AjaxApplications/Demos/Login.html


<html>
<head>
<title>Login Form</title>
<link href="Login.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">
function Login(FORM)
{
var un = FORM.Username.value;
var pw = FORM.Password.value;
new Ajax.Request("Login.jsp",
{
method: "get",
parameters: "username=" + un + "&password=" + pw,
onComplete: LoginResults
});
}

function LoginResults(REQ) //Callback Function


{
if (REQ.responseText.indexOf("failed") == -1)
{
document.getElementById("LoggedIn").innerHTML = "Logged in as " +
REQ.responseText;
document.getElementById("LoggedIn").style.display = "block";
document.getElementById("LoginForm").style.display = "none";
}
else
{
document.getElementById("BadLogin").style.display="block";
document.getElementById("LoginForm").Username.select();
document.getElementById("LoginForm").Username.className="Highlighted
";
setTimeout("document.getElementById('BadLogin').style.display='none'
",3000);
}
}
</script>
</head>
<body>

<form id="LoginForm" onsubmit="Login(this); return false">


<h1>Login Form</h1>
<div class="FormRow">
<label for="Username">Username:</label>
<input type="text" size="15" name="Username"/>
</div>
<div class="FormRow">
<label for="Password">Password:</label>
<input type="password" size="15" name="Password"/>
</div>
<div class="FormRow" id="LoginButtonDiv">
<input type="submit" value="Login"/>
</div>
<div id="BadLogin">
The login information you entered does not match an account in our
records.
Please try again.
</div>
</form>

<h1 id="LoggedIn"></h1>

</body>
</html>
Quick Lookup Form
In some cases, you need to get quick information from a database, but you don't want to
process an entire page. For example, you may have a form for requesting information
about an order. The form might have multiple fields, one of which is the order id. The
order id is not required, but if it's filled in it must match an existing order id in the
database. Rather than waiting to check the order id until the user fills out and submits the
entire form, you can use Ajax to flag a bad order id as soon as the user tabs out of that
field. A simple sample interface is shown below:

When the user enters an order id that is not in the database, an error is displayed and the

submit button becomes disabled:

When the user enters a valid order id, an icon is displayed indicating that the order id

exists and the submit button becomes enabled:

The code is shown below.

Code Sample: AjaxApplications/Demos/Lookup.html


<html>
<head>
<title>Order Lookup Form</title>
<link href="Lookup.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">
function Lookup(ORDER)
{
var orderNum = ORDER.value;
if (orderNum.length==0) //OK to submit
{
document.getElementById("OrderNumError").innerHTML="";
document.getElementById("SubmitButton").disabled=false;
return true;
}
if (isNaN(orderNum)) //Error
{
document.getElementById("OrderNumError").innerHTML="Must be
numeric.";
ORDER.style.color="red";
document.getElementById("SubmitButton").disabled=true;
return true;
}

//Look up order number in database


new Ajax.Request("Lookup.jsp",
{
method: "get",
parameters: "orderNum=" + orderNum,
onComplete: LookupResults
});
}

function LookupResults(REQ) //Callback function


{
if (REQ.responseText.indexOf("success") == -1) //Error: no match
{
document.getElementById("OrderNumError").innerHTML="No such order
number.";
document.getElementById("OrderNum").style.color="red";
document.getElementById("SubmitButton").disabled=true;
}
else //OK to submit
{
document.getElementById("OrderNumError").innerHTML="<img
src='check.gif'/>";
document.getElementById("OrderNum").style.color="green";
document.getElementById("SubmitButton").disabled=false;
}
}
</script>
</head>
<body>

<form id="LookupForm" onsubmit="alert('Form would submit.'); return


false;">
<h1>Lookup Form</h1>
<p>Enter an order number.</p>
<div class="FormRow">
<label for="Year">Order Number:</label>
<input type="text" size="10" id="OrderNum" name="OrderNum"
onblur="Lookup(this)"/>
<span id="OrderNumError"></span>
</div>
<div class="FormRow">
<label for="Year">Comments:</label><br />
<textarea name="Comments" cols="40" rows="4"></textarea>
</div>
<div class="FormRow">
<input type="submit" id="SubmitButton" value="Submit">
</div>
</form>

</body>
</html>

Code Sample: AjaxApplications/Demos/Lookup.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Northwind");

String sql = "SELECT OrderID From Orders WHERE OrderID=?";


stmt = conn.prepareStatement(sql);
stmt.setString(1, request.getParameter("orderNum"));

rs = stmt.executeQuery();
if (rs.next())
{
out.write("success");
}
else
{
out.write("failed");
}
}
catch(Exception e)
{
out.write("failed: " + e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>
Code Explanation
The server-side script simply return "success" if the order number is found or "failed" if it
is not.

Preloaded Data
Google Maps (http://maps.google.com) was one of the applications that brought so much
attention to Ajax. One of the cool things about it is that it allows the user to drag maps
around the screen seamlessly loading new sections. It does this by preloading the sections
around the map that the user is likely to drag on to the screen. This same concept can be
applied to other applications, such as slideshows and navigable tables.

Ajax Slideshow

Let's first take a look at the slideshow shown below:

When the user clicks on the Previous or Next buttons, the page makes an
XMLHttpRequest to the server, which returns XML as shown below:

The callback function creates the next slide from this XML. The code is shown below.

Code Sample: AjaxApplications/Demos/SlideShow.html


<html>
<head>
<title>Slide Show</title>
<link href="SlideShow.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">

var CurSlide=1; //Keeps track of current slide


var NumSlides = 10;

function init()
{
document.getElementById("PrevButton").onclick=PrevSlide;
document.getElementById("NextButton").onclick=NextSlide;
document.getElementById("TotalSlideNum").innerHTML = NumSlides;
GetSlide();
}

function PrevSlide()
{
if (CurSlide > 1)
{
CurSlide--;
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already showing
first slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML=''",200
0);
}
}

function NextSlide()
{
if (CurSlide < NumSlides)
{
CurSlide++;
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already showing
last slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML=''",200
0);
}
}

function GetSlide()
{
document.getElementById("CurSlideNum").innerHTML=CurSlide;

new Ajax.Request("SlideShow.jsp",
{
method: "get",
parameters: "Slide=" + CurSlide,
onComplete: ChangeSlide
});
}

function ChangeSlide(REQ) //Callback function creates slide


{
var docElem = REQ.responseXML.documentElement;
Element.cleanWhitespace(docElem);
document.getElementById("SlideText").innerHTML =
docElem.firstChild.firstChild.nodeValue + "<br/>";
document.getElementById("SlideText").innerHTML +=
docElem.childNodes[1].firstChild.nodeValue;
document.getElementById("SlideImage").src = "Slides/" +
docElem.childNodes[2].firstChild.nodeValue;
}

window.onload = init;
</script>
</head>
<body>
<h1>First 10 Presidents</h1>
<div id="Slide">
<img id="SlideImage"/>
<div id="SlideText"></div>
<form action="SlideShow.html" onsubmit="return false" id="SlideForm">
<input type="button" value="Previous" id="PrevButton"/>
Slide <span id="CurSlideNum">1</span> of <span
id="TotalSlideNum"></span>
<input type="button" value="Next" id="NextButton"/>
</form>
<div id="SlideMessage"></div>
</div>
</body>
</html>

Although this is pretty cool in and of itself, it can be made cooler by preloading the
preceding and following images, so the user experiences no delay when navigating from
slide to slide. In this case, the server-side script needs to return more data. Our script is
shown below.

Code Sample: AjaxApplications/Demos/SlideShow-


preloaded.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");

String sql = "SELECT FirstName, LastName, StartYear, EndYear,


ImagePath FROM Presidents WHERE PresidentID BETWEEN ?-1 AND ?+1";
stmt = conn.prepareStatement(sql);
stmt.setString(1, request.getParameter("Slide"));
stmt.setString(2, request.getParameter("Slide"));

rs = stmt.executeQuery();

response.setContentType("text/xml");

out.write("<Presidents>");
while (rs.next())
{
out.write("<President>");
out.write("<Name>" + rs.getString("FirstName") + " " +
rs.getString("LastName") + "</Name>");
out.write("<Years>" + rs.getString("StartYear") + "-" +
rs.getString("EndYear") + "</Years>");
out.write("<Image>" + rs.getString("ImagePath") + "</Image>");
out.write("</President>");
}
out.write("</Presidents>");
}
catch(Exception e)
{
out.write("failed: " + e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>
Code Explanation

Notice that the SQL query will return records for the chosen president, the preceding
president, and the following president. The resulting XML will look something like this:

Now we need to change the callback function to handle the preloaded slides and change
the HTML to have hidden locations for the preloaded data. The code below shows how
this is done.

Code Sample: AjaxApplications/Demos/SlideShow-


preloaded.html
<html>
<head>
<title>Slide Show</title>
<link href="SlideShow.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">

var CurSlide=1;
var NumSlides = 10;
var PrevSlideReady = false;
var NextSlideReady = false;
var CurSlideLoaded = false;

function init()
{
document.getElementById("PrevButton").onclick=PrevSlide;
document.getElementById("NextButton").onclick=NextSlide;
document.getElementById("TotalSlideNum").innerHTML = NumSlides;
GetSlide();
}

function PrevSlide()
{
if (CurSlide > 1)
{
CurSlide--;
if (PrevSlideReady) //use data from PrevSlide placeholder
{
var slideText = document.getElementById("SlideText");
var prevSlideText = document.getElementById("PrevSlideText");
var slideImage = document.getElementById("SlideImage");
var prevSlideImage = document.getElementById("PrevSlideImage");
slideText.innerHTML = prevSlideText.innerHTML;
slideImage.src = prevSlideImage.src;
//document.getElementById("SlideMessage").innerHTML = "Loaded from
PrevSlide.";
PrevSlideReady=false;
CurSlideLoaded=true;
}
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already showing
first slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML=''",200
0);
}
}

function NextSlide()
{
if (CurSlide < NumSlides)
{
CurSlide++;
if (NextSlideReady) //Use data from NextSlide placeholder
{
var slideText = document.getElementById("SlideText");
var nextSlideText = document.getElementById("NextSlideText");
var slideImage = document.getElementById("SlideImage");
var nextSlideImage = document.getElementById("NextSlideImage");
slideText.innerHTML = nextSlideText.innerHTML;
slideImage.src = nextSlideImage.src;
//document.getElementById("SlideMessage").innerHTML = "Loaded from
NextSlide.";
NextSlideReady=false;
CurSlideLoaded=true;
}
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already showing
last slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML=''",200
0);
}
}

function GetSlide()
{
document.getElementById("CurSlideNum").innerHTML=CurSlide;

new Ajax.Request("SlideShow-preloaded.jsp",
{
method: "get",
parameters: "Slide=" + CurSlide,
onComplete: ChangeSlide
});
}

function ChangeSlide(REQ)
{
var docElem = REQ.responseXML.documentElement;
var PrevSlideNode, CurSlideNode, NextSlideNode;
if (CurSlide == 1) //First slide
{
PrevSlideNode = null;
CurSlideNode = docElem.childNodes[0];
NextSlideNode = docElem.childNodes[1];
Element.cleanWhitespace(CurSlideNode);
Element.cleanWhitespace(NextSlideNode);
PrevSlideReady=false;
NextSlideReady=true;
}
else if (CurSlide == NumSlides) //Last slide
{
PrevSlideNode = docElem.childNodes[0];
CurSlideNode = docElem.childNodes[1];
Element.cleanWhitespace(PrevSlideNode);
Element.cleanWhitespace(CurSlideNode);
NextSlideNode = null;
PrevSlideReady=true;
NextSlideReady=false;
}
else
{
PrevSlideNode = docElem.childNodes[0];
CurSlideNode = docElem.childNodes[1];
NextSlideNode = docElem.childNodes[2];
Element.cleanWhitespace(PrevSlideNode);
Element.cleanWhitespace(CurSlideNode);
Element.cleanWhitespace(NextSlideNode);
PrevSlideReady=true;
NextSlideReady=true;
}

if (!CurSlideLoaded) //Use data returned from server


{
document.getElementById("SlideText").innerHTML =
CurSlideNode.childNodes[0].firstChild.nodeValue + "<br/>";
document.getElementById("SlideText").innerHTML +=
CurSlideNode.childNodes[1].firstChild.nodeValue;
document.getElementById("SlideImage").src = "Slides/" +
CurSlideNode.childNodes[2].firstChild.nodeValue;
}

if (PrevSlideNode)
{
document.getElementById("PrevSlideText").innerHTML =
PrevSlideNode.childNodes[0].firstChild.nodeValue + "<br/>";
document.getElementById("PrevSlideText").innerHTML +=
PrevSlideNode.childNodes[1].firstChild.nodeValue;
document.getElementById("PrevSlideImage").src = "Slides/" +
PrevSlideNode.childNodes[2].firstChild.nodeValue;
}

if (NextSlideNode)
{
document.getElementById("NextSlideText").innerHTML =
NextSlideNode.childNodes[0].firstChild.nodeValue + "<br/>";
document.getElementById("NextSlideText").innerHTML +=
NextSlideNode.childNodes[1].firstChild.nodeValue;
document.getElementById("NextSlideImage").src = "Slides/" +
NextSlideNode.childNodes[2].firstChild.nodeValue;
}
CurSlideLoaded=false;

window.onload = init;
</script>
</head>

<body>
<h1>First 10 Presidents</h1>
<div id="PrevSlide">
<img id="PrevSlideImage"/>
<div id="PrevSlideText"></div>
</div>
<div id="Slide">
<img id="SlideImage"/>
<div id="SlideText"></div>
<form action="SlideShow.html" onsubmit="return false" id="SlideForm">
<input type="button" value="Previous" id="PrevButton"/>
Slide <span id="CurSlideNum">1</span> of <span
id="TotalSlideNum"></span>
<input type="button" value="Next" id="NextButton"/>
</form>
<div id="SlideMessage"></div>
</div>
<div id="NextSlide">
<img id="NextSlideImage"/>
<div id="NextSlideText"></div>
</div>
</body>
</html>
Code Explanation

Notice these two divs in the HTML body:

<div id="PrevSlide">
<img id="PrevSlideImage"/>
<div id="PrevSlideText"></div>
</div>

<div id="NextSlide">
<img id="NextSlideImage"/>
<div id="NextSlideText"></div>
</div>

These divs are simply there to hold the incoming data. Their display property of these
divs is set to "none" in SlideShow.css, but if you were to comment this out, the page
would show up as follows:

The images in the upper corners are preloaded so that new slides load seamlessly.
In the JavaScript code, we have to keep track of which slide we are on.

• If we're on the first slide, then only the following slide's data has
been preloaded.
• if (CurSlide == 1)
• {
• PrevSlideNode = null;
• CurSlideNode = docElem.childNodes[0];
• NextSlideNode = docElem.childNodes[1];
• PrevSlideReady=false;
• NextSlideReady=true;
}

Notice that the global variable NextSlideReady is set to true indicating that the
next slide should be loaded from the preloaded placeholder. This is checked in the
NextSlide() function:

function NextSlide()
{
if (CurSlide < NumSlides)
{
CurSlide++;
if (NextSlideReady) //Use data from NextSlide placeholder
{
document.getElementById("SlideText").innerHTML =
document.getElementById("NextSlideText").innerHTML;
document.getElementById("SlideImage").src =
document.getElementById("NextSlideImage").src;
NextSlideReady=false;
CurSlideLoaded=true;
}
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already
showing last slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML='
'", 2000);
}
}

• If we're on the last slide, then only the previous slide's data is
preloaded.
• else if (CurSlide == NumSlides)
• {
• PrevSlideNode = docElem.childNodes[0];
• CurSlideNode = docElem.childNodes[1];
• NextSlideNode = null;
• PrevSlideReady=true;
• NextSlideReady=false;
}
The global variable PrevSlideReady is set to true indicating that the previous slide
should be loaded from the preloaded placeholder. This is checked in the
PrevSlide() function:

function PrevSlide()
{
if (CurSlide > 1)
{
CurSlide--;
if (PrevSlideReady) //Use data from PrevSlide placeholder
{
document.getElementById("SlideText").innerHTML =
document.getElementById("PrevSlideText").innerHTML;
document.getElementById("SlideImage").src =
document.getElementById("PrevSlideImage").src;
PrevSlideReady=false;
CurSlideLoaded=true;
}
GetSlide();
}
else
{
document.getElementById("SlideMessage").innerHTML = "Already
showing first slide.";
setTimeout("document.getElementById('SlideMessage').innerHTML='
'",2000);
}
}

• For all other slides, both the previous and following slides' data is
preloaded.
• else
• {
• PrevSlideNode = docElem.childNodes[0];
• CurSlideNode = docElem.childNodes[1];
• NextSlideNode = docElem.childNodes[2];
• PrevSlideReady=true;
• NextSlideReady=true;
}

Both NextSlideReady and PrevSlideReady are set to true.

Note that in the NextSlide() and PrevSlide() functions, CurSlideLoaded is set to true after
a slide is loaded from preloaded data. This variable is checked in the ChangeSlide()
function to decide whether or not to load the current slide from the newly downloaded
data:

if (!CurSlideLoaded) //Use the data returned from the server


{
document.getElementById("SlideText").innerHTML =
CurSlideNode.childNodes[0].firstChild.nodeValue + "<br/>";
document.getElementById("SlideText").innerHTML +=
CurSlideNode.childNodes[1].firstChild.nodeValue;
document.getElementById("SlideImage").src = "Slides/" +
CurSlideNode.childNodes[2].firstChild.nodeValue;
}

Navigable Tables

The same techniques can be used to create navigable tables like the one shown below:

This screenshot shows the preloaded rows with a gray background. In practice, these
rows would be hidden. Open AjaxApplications/Solutions/TableRows.html in your
browser to try it out. To hide the preloaded rows, change the following lines in
TablesRows.html:

<tbody id="PrevRows" style="background-color:gray;"></tbody>


<tbody id="CurRows"></tbody>
<tbody id="NextRows" style="background-color:gray"></tbody>

...to...

<tbody id="PrevRows" style="display:none;"></tbody>


<tbody id="CurRows"></tbody>
<tbody id="NextRows" style="display:none"></tbody>

Ajax Applications Conclusion


In this lesson of the Ajax tutorial, you have learned to apply some of the Ajax techniques
you have learned.

To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents

JavaScript is an object-oriented programming language; however, as we'll see, its


approach to objects is somewhat different than most of the other mainstream object-
oriented languages. Prototype, which we have been using to handle our Ajax requests,
makes use of JavaScript's object-oriented features. We have seen its Ajax object with a
request() method that makes it very easy to make calls with the XMLHttpRequest object
that work on most major browsers. In this lesson, we'll see why it is so useful to handle
these requests in an object-oriented way. We'll start by taking a look at an example that
illustrates the need to handle simultaneous requests. We'll then look at writing object-
oriented JavaScript code. And we'll finish the lesson by creating our own object-oriented
code for handling XMLHttpRequests.

Illustrating the Problem


The screenshot below shows a simple Ajax-based quiz.

1. When the user clicks a radio button, a request is made to the server using the GET
method and sending the radio button's name (e.g, "q1") and the value (e.g, 3).
2. The server returns either "Right" or "Wrong" as the status text.
3. A message is displayed next to the appropriate question indicating whether or not
the user answered the question correctly.

That seems straightforward enough. Let's look at the code.

Code Sample: OOP/Demos/AjaxQuiz.html


<html>
<head>
<link href="AjaxQuiz.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="Ajax.js"
type="text/javascript"></script>
<script type="text/javascript">
var xmlhttp, OutputResult;
function init()
{
var quiz=document.getElementById("quizForm");
var inputs = quiz.getElementsByTagName("input");
for (i=0; i<inputs.length; i++)
{
inputs[i].onclick=CheckAnswer;
}
}

function Respond()
{
if (Math.floor(Math.random(3) * 3) == 1) //creates artificial delay 1
out of 3 times
{
setTimeout("OutputResult.innerHTML=xmlhttp.responseText",3000);
}
else
{
OutputResult.innerHTML=xmlhttp.responseText;
}
}

function SendRequest(Q,A)
{
xmlhttp = GetReq();
xmlhttp.open("GET","AjaxQuiz.jsp?q=" + Q + "&a=" + A,true);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
Respond();
}
}
xmlhttp.send(null);
}

function CheckAnswer(e)
{
if (!e) e = window.event;
var target = e.target || e.srcElement;
var q = target.name;
var a = target.value;
OutputResult = document.getElementById(q + "Result");
OutputResult.innerHTML="checking...";
SendRequest(q,a);
}

window.onload=init;
</script>
<title>Ajax Quiz</title>
</head>

<body>
<h1>Ajax Quiz</h1>
<form onsubmit="return false" id="quizForm">
<div class="WholeQuestion">
<div class="Question">
What is 1 + 1?
</div>
<div class="Answer">
<input type="radio" name="q1" value="1" /> 1
<input type="radio" name="q1" value="2" /> 2
<input type="radio" name="q1" value="3" /> 3
</div>
<div class="Result" id="q1Result"></div>
</div>
<div class="WholeQuestion">
<div class="Question">
What is 1 + 2?
</div>
<div class="Answer">
<input type="radio" name="q2" value="1" /> 1
<input type="radio" name="q2" value="2" /> 2
<input type="radio" name="q2" value="3" /> 3
</div>
<div class="Result" id="q2Result"></div>
</div>
<div class="WholeQuestion">
<div class="Question">
What is 2 - 1?
</div>
<div class="Answer">
<input type="radio" name="q3" value="1" /> 1
<input type="radio" name="q3" value="2" /> 2
<input type="radio" name="q3" value="3" /> 3
</div>
<div class="Result" id="q3Result"></div>
</div>
</form>
</body>
</html>

And for those interested, the server-side code:

Code Sample: OOP/Demos/AjaxQuiz.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%
String question = request.getParameter("q").substring(1);
String answer = request.getParameter("a");

try
{
switch (Integer.parseInt(question)) //evaluates to an integer
{
case 1 :
if (answer.equals("2"))
{
out.write("Right");
}
else
{
out.write("Wrong");
}
break;
case 2 :
if (answer.equals("3"))
{
out.write("Right");
}
else
{
out.write("Wrong");
}
break;
case 3 :
if (answer.equals("1"))
{
out.write("Right");
}
else
{
out.write("Wrong");
}
break;
default:
out.write("Failed");
}
}
catch (Exception e)
{
out.write("Failed: " + e.toString());
}
%>
Code Explanation

1. In the first line of JavaScript code, two global variables are


declared: xmlhttp and OutputResult, which will hold the
XMLHttpRequest object and the div for outputting the message from the
server, respectively.
2. The init() function, which is called whent the page loads, attaches
events to all input elements (the radio buttons) on the page, so that when
they are clicked the CheckAnswer() function is called.
3. CheckAnswer() gets the question and selected answer, sets
OutputDiv to that answer's corresponding result div, outputs "checking..."
to the newly set OutputResult div, and passes the question and answer to
SendRequest().
4. SendRequest() creates an XMLHttpRequest object using the
GetReq() function in the Ajax.js library. It opens the request using the
GET method to pass the question and selected answer to AjaxQuiz.jsp.
When the server response is complete, the Respond() function is called.
5. Respond() simply outputs the returned status text to the
OutputResult div. It randomly creates an artificial delay. This is to
demonstrate how our xmlhttp variable can get stolen by a subsequent call
before the current call is complete.

And everything works beautifully. Well, almost. What happens when one of the requests
or responses is delayed and, in the meantime, the user answers another question. Here's
the scenario:

1. The user clicks on an answer, resulting in a call to CheckAnswer()


(step 3 above). This sets the global OutputResult variable to that answer's
corresponding result div. It then calls SendRequest().
2. SendRequest() makes the call to the server and waits for a
response, which takes a long time.
3. Meanwhile, our very quick user answers the next question. This
calls CheckAnswer() again, which changes the OutputResult div.
4. OutputResult = document.getElementById(q +
"Result");
5. OutputResult.innerHTML="checking...";
6. SendRequest(q,a);

If the server response were to complete at the very next moment (between the two
highlighted lines above), the result of the first call would be written to the wrong
result div.

7. More than likely, however, the server response won't hit in the
couple milliseconds between the time the OutputResult div is changed and
SendRequest() is called, creating a brand new XMLHttpRequest object
and assigning it to the same global xmlhttp variable. This means the old
XMLHttpRequest object, which was still waiting for the server response,
gets destroyed, leaving nobody to handle that response. The result div for
that question will never get updated, being left with the text "checking..."
until the user responds to that question again.

So, how do we deal with this problem? We could simply store each new request in a new
variable and associate the correct result div with with that request. But we don't know
how many variables to create because we don't know how many requests will be made.
We could create an array of requests, appending each new request as its made. While this
might do the trick for this simple example, it would get difficult to manage as the code
became more complex. A better solution lies in object-oriented programming. Before we
look at the solution though, we need to learn to create and manage objects in JavaScript.

Object-Oriented JavaScript
Creating new objects in JavaScript is straightforward. The code below shows how to
create a simple Cat object.

Code Sample: OOP/Demos/SimpleObject.html


<html>
<head>
<script type="text/javascript">
var Cat = new Object();

Cat.name = "Socks";
Cat.color = "white";
Cat.formerOwners = new Array("Fred","Abe","Julie");
Cat.meow = function()
{
alert("Meow");
}
</script>
<title>Simple Object</title>
</head>

<body>
<a href="javascript:void(0)" onclick="Cat.meow();">Cat Sound</a>
</body>
</html>
Code Explanation

Click on the "Cat Sound" link and the cat meows. This is a pretty useless object. Now
let's see how to create a pretty useless class. Don't worry, we'll create some useful ones
later on.

JavaScript Classes

A class is a template used to define the methods and properties of a particular type of
object. For example, an Animal class could be used to define methods and properties
common to all animals. The following example shows how to define a class and
instantiate an object of that class.

Code Sample: OOP/Demos/Class.html


<html>
<head>
<script type="text/javascript">

function Animal(NAME,COLOR,OWNERS,SOUND)
{
this.name = NAME;
this.color = COLOR;
this.formerOwners = OWNERS;
this.communicate = function()
{
alert(SOUND);
}
}
var Owners = new Array("Fred","Abe","Julie");
var Cat = new Animal("Socks","white",Owners,"meow");
var Dog = new Animal("Spot","brown",Owners,"ruff");

</script>
<title>Simple Class</title>
</head>

<body>
<a href="javascript:void(0)" onclick="Cat.communicate();">Cat Sound</a>
<a href="javascript:void(0)" onclick="Dog.communicate();">Dog Sound</a>
</body>
</html>
Code Explanation

Classes make it easy to create similar objects that vary in specific ways. Cats say
"meow." Dogs say "ruff." The class constructor is simply a function that looks just like
any other JavaScript function. Objects are instantiated with the keyword new followed by
a call to that function. In the class definition, the keyword this is used to refer to the
newly instantiated object.

The class we've created has a communicate() method, which is how we get our cats and
dogs to meow and bark. Although this works fine, there is a downside to creating
methods in this way: every time a new object is created, the method is recreated and
stored in memory. 100 animals means 100 communicate() methods.

Prototypes

Every class, including the built-in classes, has a prototype property, which holds all the
members that objects of that class will have. This way, members do not get redefined
each time an object is instantiated. The example below shows how prototypes are created.

Code Sample: OOP/Demos/Prototype.html


<html>
<head>
<script type="text/javascript">

function Animal(NAME,COLOR,OWNERS,SOUND)
{
this.name = NAME;
this.color = COLOR;
this.formerOwners = OWNERS;
this.sound = SOUND;
}

Animal.prototype.communicate = function()
{
alert(this.sound);
}

var Owners = new Array("Fred","Abe","Julie");


var Cat = new Animal("Socks","white",Owners,"meow");
var Dog = new Animal("Spot","brown",Owners,"ruff");
</script>
<title>Simple Class</title>
</head>

<body>
<a href="javascript:void(0)" onclick="Cat.communicate();">Cat Sound</a>
<a href="javascript:void(0)" onclick="Dog.communicate();">Dog Sound</a>
</body>
</html>

Extending Built-in Objects

Built-in objects can be extended with prototypes. This can be a bit dangerous as it may
affect code that relies on a specific set of properties in the prototype; however, it also can
be useful. The code below shows how to add a display() method to the Array object. It is
not a very exciting method, but it illustrates the technique.

Code Sample: OOP/Demos/ExtendingBuiltInObjects.html


<html>
<head>
<script type="text/javascript" type="text/javascript">
Array.prototype.display = function()
{
var strItems = "Array Items: \n";
for (var i=0; i < this.length; i++)
{
strItems += " * " + this[i] + "\n";
}
alert(strItems);
}

var Letters=new Array("A","B","C");


Letters.display();
</script>
<title>Extending Built-in Objects</title>
</head>

<body>
</body>
</html>

Refactoring the Ajax Request Code


Let's now return to our XMLHttpRequest calls. Earlier in this lesson, we looked at an
Ajax-based quiz that uses a global variable to hold the XMLHttpRequest object. The
problem with this is that that variable gets overwritten every time a new call is made,
leaving any incomplete calls stranded. Now we'll take a look at an object-oriented
approach to creating XMLHttpRequest calls.

The code below is based heavily on Dave Crane's ContentLoader class defined in Ajax in
Action.

Code Sample: OOP/Demos/ContentLoader.js


/*
Function Name: ContentLoader
Arguments:
URL: the URL to which the request is sent
METHOD: the method used to send the request. If this is set to JSON
or XML, the POST method will be used.
CALLBACK: the function to call when the server response is complete
RESULTDIV: the name of the div that will contain the output
PARAMS: an object with properties and values
Returns: Nothing
Notes: Used to create and send an XMLHttpRequest object and call a
specified callback function when the server response is complete.
*/
function ContentLoader(URL,METHOD,CALLBACK,RESULTDIV,PARAMS)
{
this.xmlhttp=null;
this.url = URL;
this.method = (typeof METHOD == "undefined" || typeof METHOD ==
null) ? "GET" : METHOD.toUpperCase();
this.callBack=CALLBACK;
this.resultDiv = (typeof RESULTDIV == "string") ?
document.getElementById(RESULTDIV) : RESULTDIV;
this.params = (typeof PARAMS == "undefined") ? null : PARAMS;
this._loadAjax();
}

ContentLoader.prototype._loadAjax=function()
{
var PostQS;
if (this.method=="POST")
{
PostQS = this._createQueryString();
}
else //GET OR HEAD
{
this.url = this.url + "?" + this._createQueryString();
PostQS = null;
}

if ( this.xmlhttp=this._createXHR() )
{
try
{
var loader=this;
this.xmlhttp.onreadystatechange=function()
{
loader._onReadyState.call(loader);
}
this.xmlhttp.open(this.method,this.url,true);

if (this.method=="POST")
{
this.xmlhttp.setRequestHeader("Content-Type","application/x-www-
form-urlencoded;");
}
this.xmlhttp.send(PostQS);
}
catch(exc)
{
alert("ERROR: " + exc.message);
}
}
else
{
alert("ERROR: AJAX NOT SUPPORTED");
}
}

ContentLoader.prototype._onReadyState=function()
{
if (this.xmlhttp.readyState==4 && this.xmlhttp.status == 200)
{
if (this.callBack) this.callBack.call(this);
}
else if (this.xmlhttp.readyState==4)
{
alert("Error: " + this.xmlhttp.responseText);
}
}

/*
Function Name: _createXHR
Arguments: none
Returns: browser-specific xmlhttp object or false
*/
ContentLoader.prototype._createXHR=function()
{
try
{
xmlhttp = new XMLHttpRequest();
}
catch(exc1)
{
var ieXmlHttpVersions = new Array();
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.7.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.6.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.5.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.4.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp.3.0";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "MSXML2.XMLHttp";
ieXmlHttpVersions[ieXmlHttpVersions.length] = "Microsoft.XMLHttp";

var i;
for (i=0; i < ieXmlHttpVersions.length; i++)
{
try
{
xmlhttp = new ActiveXObject(ieXmlHttpVersions[i]);
break;
}
catch (exc2)
{
alert(ieXmlHttpVersions[i] + " not supported.");
}
}
}
return xmlhttp;
}

ContentLoader.prototype._createQueryString=function()
{
var qs="timestamp=" + new Date().getTime();
if (typeof this.params == "object") //if no arguments are passed,
arguments has a length of 1 and arguments[0] is undefined.
{
for (i in this.params)
{
qs += "&" + i + "=" + this.params[i];
}
}
return qs;
}
Code Explanation

This ContentLoader() constructor takes five arguments:

• URL: the URL to which the request is sent.


• METHOD: the method used to send the request.
• CALLBACK: the function to call when the server response is
complete.
• RESULTDIV: the name of the element that will contain the output.
• PARAMS: an object with properties and values.

The class has the following other methods :

• _loadAjax() - This is the main method. It uses the methods listed


below to create and send the request.
• _onReadyState() - This method calls the callback function when
the response is complete.
• _createXHR() - This method creates a browser-specific xmlhttp
object.
• _createQueryString() - This method creates a querystring from the
PARAMS parameter passed in.

The example below shows how the ContentLoader class abstracts all the code for making
XMLHttpRequest calls into a reusable and flexible class that works across browsers.

Code Sample: OOP/Demos/UsingContentLoader.html


<html>
<head>
<title>Using ContentLoader</title>
<script src="ContentLoader.js" type="text/javascript"></script>
<script type="text/javascript">
function SayHi(FNAME,LNAME) //Passes values via an object (params)
{
var params = new Object();
params["FirstName"] = FNAME;
params["LastName"] = LNAME;

new ContentLoader("Demo.jsp","POST",Loaded,"Content",params);
}

function Loaded()
{
var resultDiv = this.resultDiv;
var xmlhttp = this.xmlhttp;
if (Math.floor(Math.random(3) * 3) == 1) //creates artificial delay 1
out of 3 times
{
setTimeout(function() { resultDiv.innerHTML +=
xmlhttp.responseText; },3000);
}
else
{
resultDiv.innerHTML += xmlhttp.responseText;
}
}
</script>
</head>
<body>
<a href="javascript:SayHi('Paul','McCartney')">Paul</a>
<a href="javascript:SayHi('John','Lennon')">John</a>
<a href="javascript:SayHi('Ringo','Starr')">Ringo</a>
<a href="javascript:SayHi('George','Harrison')">George</a>
<ol id="Content"></ol>
</body>
</html>
Code Explanation

This file contains two JavaScript functions: SayHi(), which creates a new ContentLoader
object and Loaded() the object's callback function. The callback function outputs a new
list item to the Content list. An artificial delay is created randomly to simulate a delayed
response. Open UsingContentLoader.html in your browser and click on the links. You
will notice the delayed response items get added to the list as soon as they are complete.
If we were to do this using a global variable to hold the xmlhttp object (as we saw in
OOP/Demos/AjaxQuiz.html), the items would not have been added because the variable
would have been overwritten by the next call.

OO JavaScript and Refactoring Ajax


Conclusion
In this lesson of the Ajax tutorial you have learned to use object-oriented programming in
JavaScript to handle multiple simultaneous asynchronous requests.

To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

Object Literals
We saw earlier how to create new objects in JavaScript with the Object() constructor. We
also saw how we could create our constructors for our own objects. In this lesson, we'll
examine JavaScript's literal syntax for creating arrays and objects.
Arrays

Array literals are created with square brackets as shown below:

var Beatles = ["Paul","John","George","Ringo"];

This is the equivalent of:

var Beatles = new Array("Paul","John","George","Ringo");

Objects

Object literals are created with curly brackets:

var Beatles = {
"Country" : "England",
"YearFormed" : 1959,
"Style" : "Rock'n'Roll"
}

This is the equivalent of:

var Beatles = new Object();


Beatles.Country = "England";
Beatles.YearFormed = 1959;
Beatles.Style = "Rock'n'Roll";

Just as with all objects in JavaScript, the properties can be references using dot notation
or bracket notation.

alert(Beatles.Style); //Dot Notation


alert(Beatles["Style"]); //Bracket Notation

Arrays in Objects

Object literals can contain array literals:

var Beatles = {
"Country" : "England",
"YearFormed" : 1959,
"Style" : "Rock'n'Roll",
"Members" : ["Paul","John","George","Ringo"]
}

Objects in Arrays

Array literals can contain object literals:

var Rockbands = [
{
"Name" : "Beatles",
"Country" : "England",
"YearFormed" : 1959,
"Style" : "Rock'n'Roll",
"Members" : ["Paul","John","George","Ringo"]
},
{
"Name" : "Rolling Stones",
"Country" : "England",
"YearFormed" : 1962,
"Style" : "Rock'n'Roll",
"Members" : ["Mick","Keith","Charlie","Bill"]
}
]

JSON
On the JSON website (http://www.json.org), JSON is described as:

1. a lightweight data-interchange format


2. easy for humans to read and write
3. easy for machines to parse and generate

Numbers 1 and 3 are certainly true. Number 2 depends on the type of human.
Experienced programmers will find that they can get comfortable with the syntax
relatively quickly.

JSON Syntax

The JSON syntax is like JavaScript's object literal syntax except that the objects cannot
be assigned to a variable. JSON just represents the data itself. So, the Beatles object we
saw earlier would be defined as follows:

{
"Name" : "Beatles",
"Country" : "England",
"YearFormed" : 1959,
"Style" : "Rock'n'Roll",
"Members" : ["Paul","John","George","Ringo"]
}

JSON Parsers

As JSON is just a string of text and not an object in and of itself, it needs to be converted
to an object before to make it useful. Although this can be done in JavaScript with the
eval() function, it is safer to use a JSON parser. You can download the JavaScript JSON
parser at http://www.json.org/json.js. Including this file on a web page allows you to take
advantage of the JSON object, which has the following very useful methods:
• JSON.parse(strJSON) - converts a JSON string into a JavaScript object.
• JSON.stringify(objJSON) - converts a JavaScript object into a JSON string.

The process for sending data between the browser and server with JSON is as follows:

1. On the client-side:
o Create a JavaScript object using the standard or literal syntax.
o Use the JSON parser to stringify the object.
o Send the URL-encoded JSON string to the server as part of the HTTP
Request. This can be done using the HEAD, GET or POST method by
assigning the JSON string to a variable. It can also be sent as raw text
using the POST method, but this may create extra work for you on the
server-side.
2. On the server-side:
o Decode the incoming JSON string and convert the result to an object using
a JSON parser for the language of your choice. At http://www.json.org,
you'll find JSON parsers for many modern programming languages. The
methods available depend upon which parser you are using. See the
parser's documentation for details.
o Do whatever you wish with the object.
o If you wish to send JSON back to the client:
 Create a new object for storing the response data.
 Convert the new object to a string using your JSON parser.
 Send the JSON string back to the client as the response body (e.g,
Response.Write(strJSON), echo $strJSON, out.write(strJSON)
etc.).
3. On the client-side:
o Convert the incoming JSON string to an object using the JavaScript JSON
parser.
o Do whatever you wish with the object.
o And so on...

The examples below show how to transfer data to the server using JSON.

Code Sample: JSON/Demos/SendJson.html


<html>
<head>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript" src="../../json.js"></script>
<script type="text/javascript">
function SendRequest(MSG)
{
document.getElementById("ResponseDiv").innerHTML="";
var objJSON = {
"msg" : MSG
};
var strJSON = encodeURIComponent(JSON.stringify(objJSON));
new Ajax.Request("ReceiveJSON.jsp",
{
method: "post",
parameters: "strJSON=" + strJSON,
onComplete: Respond
});
}

function Respond(REQ)
{
document.getElementById("ResponseDiv").innerHTML=REQ.responseText;
}
</script>
<title>Using JSON</title>
</head>

<body>
<h1>Request</h1>
<form>
<input type="button" value="Hi There!"
onClick="SendRequest(this.value)"/>
<input type="button" value="Good bye!"
onClick="SendRequest(this.value)" />
</form>
<h1>Response</h1>
<div id="ResponseDiv">Waiting...</div>
</body>
</html>

Code Sample: JSON/Demos/ReceiveJSON.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.net.*,org.json.simple.*"%>
<%
try
{
URLDecoder decoder = new URLDecoder();
String strJSON = decoder.decode(request.getParameter("strJSON"));
JSONObject objJSON = (JSONObject) JSONValue.parse(strJSON);

String Message = objJSON.get("msg").toString();


if (Message.equals("Hi There!"))
{
out.write("And hi there to you!");
}
else
{
out.write("Later Gator!");
}
}
catch (Exception e)
{
out.write(e.toString());
}
%>
Code Explanation
This code is relatively simple. The client-side script:

• creates a simple JSON object with one property holding the passed in MSG string.
• converts the JSON object to a string and encodes it.
• passes the string as a parameter of our Ajax request (using Prototype).
• outputs the responseText to the page.

The server-side script:

• decodes the passed in string and converts it to a JSON object.


• outputs an appropriate response.

JSON Advantages and Disadvantages


Advantages

JavaScript Syntax

The fact that JSON uses JavaScript syntax is the biggest advantage. It makes it extremely
easy to work with on the client side. Compare this to traversing the XML DOM or XSLT
and you'll find great efficiencies in working with JSON.

Brevity

Another oft-touted advantage of JSON is that it is lightweight. Compare, for example, the
Rockbands object we saw earlier in the lesson in JSON vs. XML:

//JSON
[
{
"Name" : "Beatles",
"Country" : "England",
"YearFormed" : 1959,
"Style" : "Rock'n'Roll",
"Members" : ["Paul","John","George","Ringo"]
},
{
"Name" : "Rolling Stones",
"Country" : "England",
"YearFormed" : 1962,
"Style" : "Rock'n'Roll",
"Members" : ["Mick","Keith","Charlie","Bill"]
}
]

//XML
<Rockbands>
<Rockband>
<Name>Beatles</Name>
<Country>England</Country>
<YearFormed>1959</YearFormed>
<Members>
<Member>Paul</Member>
<Member>John</Member>
<Member>George</Member>
<Member>Ringo</Member>
</Members>
</Rockband>
<Rockband>
<Name>Rolling Stones</Name>
<Country>England</Country>
<YearFormed>1962</YearFormed>
<Members>
<Member>Mick</Member>
<Member>Keith</Member>
<Member>Charlie</Member>
<Member>Bill</Member>
</Members>
</Rockband>
</Rockbands>

The XML representation has almost twice as many characters. While for long files, this
may be significant, in most cases this will not cause any noticeable difference. Further, if
you were to represent the XML with attributes rather than elements, the difference would
be much less.

Disadvantages

New Syntax - Not So Human Readable

The biggest disadvantage of working with JSON is it is yet another syntax we need to
familiarize ourselves with. However, with a little effort, most developers will find it's not
too difficult to get comfortable with.

Not "XPathable"

XPath makes it possible to search through XML documents and find specific node values
based on many different criteria (e.g, relative location to other nodes in the document).
JavaScript objects and arrays have no comparable built-in capability.

JavaScript Object Notation (JSON)


Conclusion
In this lesson of the Ajax tutorial, you have learned how to work with JSON to transfer
data to and from the server. As you develop Ajax applications, you'll find JSON an
excellent tool to have in your kit.
To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.

Inline Editing
Sometimes it is nice to be able to edit a page without displaying form elements by
default. For example, if you want to allow people who are logged in as administrators to
edit sections of a page, you could make it so that the administrator could click on those
sections to turn them into form elements.

Our example below shows a simple table showing the presidents' first and last names:
The neat thing about this table is that the names become editable when clicked:

All the user has to do is type a new value and click on the edit icon to change the value in
the table. An XMLHttpRequest is used to change the record in the database. The code is
shown below.

Code Sample: MoreAjaxApps/Demos/Presidents.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<html>
<head>
<title>Row to Form</title>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript" src="../../sarissa.js"></script>
<script type="text/javascript" src="InlineEditing.js"></script>
<link type="text/css" rel="stylesheet" href="Presidents.css"/>
</head>

<body>
<form onsubmit="return false">
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");

String sql = "SELECT PresidentID, FirstName, LastName FROM


Presidents";
stmt = conn.prepareStatement(sql);

rs = stmt.executeQuery();
out.write("<h1>Presidents</h1>");
out.write("<table cellpadding='2' cellspacing='0'>");
while (rs.next())
{
out.write("<tr id='" + rs.getString("PresidentID") + "'>");
out.write("<td onclick='Cell2Form(this)' title='FirstName'>" +
rs.getString("FirstName") + "</td>");
out.write("<td onclick='Cell2Form(this)' title='LastName'>" +
rs.getString("LastName") + "</td>");
out.write("</tr>");
}
out.write("</table>");
}
catch(Exception e)
{
out.write("failed: " + e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>
</form>
</body>
</html>
Code Explanation

The code queries the database for the presidents' first and last names and then iterates
through the resultset creating a table row for each president. Clicking a table cell will call
the Cell2Form() function, passing in the table cell itself.

Code Sample: MoreAjaxApps/Demos/InlineEditing.js


function Cell2Form(CELL)
{
if (CELL.firstChild.nodeType == 1)
{
return true;
}
var strXML = "<td>" + CELL.innerHTML + "</td>";
var strXslPath = "Cell2Form.xsl";

new Ajax.Request(strXslPath,
{
method: "get",
onComplete: _transform
});

function _transform(REQ)
{
var strForm = Transform(strXML,REQ.responseXML);
CELL.innerHTML=strForm;
CELL.firstChild.firstChild.select();
}
}

function Transform(strXML,docXSL)
{
var parser = new DOMParser();
var xml = parser.parseFromString(strXML,"text/xml");
xml.async=false;
var processor = new XSLTProcessor();
processor.importStylesheet(docXSL);
var xmlDom = processor.transformToDocument(xml);

var serializer = new XMLSerializer();


var result = serializer.serializeToString(xmlDom.documentElement);
return result;
}

function SaveAndClose(CELL)
{
var cellName = CELL.title;
var cellValue = CELL.firstChild.firstChild.value;
var presID = CELL.parentNode.id;
new Ajax.Request("SaveCell.jsp",
{
method: "get",
parameters: "field=" + cellName + "&value=" + cellValue + "&pid=" +
presID,
onComplete: _result
});

function _result(REQ)
{
if (REQ.responseText.indexOf("success") >= 0)
{
CELL.innerHTML = cellValue;
Blink(CELL,1000,"Saved","Normal");
}
else
{
alert(REQ.responseText);
}
}
}

function Blink(ELEM,TIME,ON,OFF,TIMEPAST)
{
var timePast = (typeof TIMEPAST != "undefined") ? TIMEPAST + 100 : 0;
ELEM.className = (ELEM.className == ON) ? OFF : ON;

if (timePast < TIME)


{
setTimeout(function () { Blink(ELEM,TIME,ON,OFF,timePast) },100);
}
else
{
ELEM.className = OFF;
}
}
Code Explanation

This is the JavaScript library. It has the following functions:

• Cell2Form()
1. Creates a simple XML string containing the content of the
clicked cell wrapped in <td></td> tags.
2. Uses prototype to load Cell2Form.xsl, which will be used
to transform the XML string to an form control and then call the
private _transform() function when the file is finished loading.
 _transform()
 Passes the XML string and the
responseXML to the public Transform() function
and assigns the value (a form control) to strForm.
 Writes strForm to the innerHTML property
of the clicked cell. Now the cell contains the form
control (and the edit image).
 Selects the text inside the form control so
that the user can begin editing immediately.
• Transform()
1. Uses sarissa to transform the passed-in XML string against
the passed in XSLT document.
• SaveAndClose() - This function is called when the edit button is
clicked.
1. Uses prototype to send the name and value of the field
being edited (e.g, FirstName or LastName) and the associated
PresidentID.
2. The callback function (_result()) simply writes out the field
name to the cell and calls the Blink() function.
• Blink()
1. Toggles the class name of the passed in element (ELEM)
between the passed-in ON and OFF values for TIMEPAST
milliseconds. This creates a blinking effect.

The SaveCell.jsp and Cell2Form.xsl files are shown below. The former updates the
database. The latter transforms a data cell with text to a data cell with a form input
element and image submit button.
Code Sample: MoreAjaxApps/Demos/SaveCell.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");

String field = request.getParameter("field");


String value = request.getParameter("value").replaceAll("'","''");
String presID = request.getParameter("pid");
String sql = "UPDATE Presidents SET " + field + " = ? WHERE
PresidentID = ?";

stmt = conn.prepareStatement(sql);
stmt.setString(1, value);
stmt.setString(2, presID);

stmt.executeUpdate();
out.write("success");
}
catch (Exception e)
{
out.write("Failed:\n\n " + e.toString());
}
finally
{
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>

Code Sample: MoreAjaxApps/Demos/Cell2Form.xsl


<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="td"/>
</xsl:template>
<xsl:template match="td">
<div>
<input type="text" value="{.}"/>
<input type="image" title="Save and Close"
onclick="SaveAndClose(this.parentNode.parentNode)" src="Edit.gif" />
</div>
</xsl:template>

</xsl:stylesheet>

Detailed Information on Demand


Netflix, the online movie rental company, has a cool feature on their website
(http://www.netflix.com) that allows users to hover over a picture of a movie to get more
detailed information about that movie. This makes it possible to give users the detailed
information they want without downloading detailed information about every movie
shown on the page. A screenshot is shown below:
We've done something similar (though not as fancy) with our Presidents page:

The code is shown below.

Code Sample: MoreAjaxApps/Demos/TableRowsMoreInfo.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");
String sql = "SELECT PresidentID, FirstName, LastName, StartYear,
EndYear, ImagePath FROM Presidents";
stmt = conn.prepareStatement(sql);

rs = stmt.executeQuery();
%>

<html>
<head>
<title>Table Rows - More info</title>
<link href="TableRowsMoreInfo.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript">
function GetBio(TR,ID)
{
var bioDiv=document.getElementById("Bio");

new Ajax.Request("Bio.jsp",
{
method: "get",
parameters: "id=" + ID,
onComplete: _showBio
})

function _showBio(REQ)
{
bioDiv.innerHTML = REQ.responseText;
}

bioDiv.style.marginTop = (ID * 50) + "px"; //position element (hack)


bioDiv.style.visibility="visible";
}

function HideBio(TR)
{
var bioDiv=document.getElementById("Bio");
bioDiv.style.visibility="hidden";
bioDiv.innerHTML="";
}

</script>
</head>

<body>
<h1>First 10 Presidents</h1>
<table id="Table" cellspacing="0">
<thead>
<tr>
<th style="width:120px">President</th>
<th style="width:60px">Years</th>
<th style="width:50px">Image</th>
</tr>
</thead>
<tbody>
<%
while (rs.next())
{
%>
<tr valign="top">
<td><%=rs.getString("FirstName") + " " + rs.getString("LastName")
%></td>
<td><%=rs.getString("StartYear")%>-<%=rs.getString("EndYear")%></td>
<td onMouseOver="GetBio(this,<%=rs.getString("PresidentID")%>)"
onMouseOut="HideBio(this)" style="cursor:pointer"><img src="Images/<
%=rs.getString("ImagePath")%>"/></td>
</tr>
<%
}
%>
</tbody>
</table>
<div id="Bio"></div>
</body>
</html>
<%
}
catch(Exception e)
{
out.write("failed: " + e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>

Code Sample: MoreAjaxApps/Demos/Bio.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");

String sql = "SELECT Bio FROM Presidents WHERE PresidentID=?";


stmt = conn.prepareStatement(sql);
stmt.setString(1, request.getParameter("id"));

rs = stmt.executeQuery();
if (rs.next())
{
out.write(rs.getString("Bio"));
}
else
{
out.write("No president selected");
}
}
catch (Exception e)
{
out.write(e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>
Code Explanation
This TableRowsMoreInfo.jsp file creates the presidents HTML table. The cell containing
the image has a mouseover event that creates a call to the GetBio() function, which uses
Prototype/Ajax to call Bio.jsp and get the biography of the associated president.

Autologout
If a user is idle for a certain amount of time, it is often a good idea to force a logout,
especially if there might be sensitive data on the screen. This is normally handled on the
server side; however, if we want to hide the data on the screen and alert the user that the
session has ended, we'll need to handle the session on the client as well. One way to
handle this is described below:

1. When the user logs in, create a JavaScript timer with the window.setTimeout()
method. The timer will call a function that ends the session after n minutes.
2. Whenever there is user activity, the timer must be restarted.
3. When the user explicitly logs out (e.g, clicks on a logout button), the timer must
be killed.

To illustrate, we will be forcing the presidents to login to our inline editing application.
The logins are all first initial - lastname (e.g, "gwashington") and the passwords are all
the word "password". First, let's look at the application. It starts with a simple login form:
When the user logs in, the editable table appears. We also provide a Logout button, so the
user can log himself out.
When the session times out, the page goes blank and an alert appears informing the user
that the session has timed out:

After the user clicks on the OK button, the login form reappears. Let's look at the code.
There are quite a few files involved. The main page is shown below:

Code Sample: MoreAjaxApps/Demos/PresidentsLogin.html


<html>
<head>
<title>Authentication</title>
<link href="Login.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript" src="../../sarissa.js"></script>
<script type="text/javascript" src="DOM.js"></script>
<script type="text/javascript" src="InlineEditing2.js"></script>
<script type="text/javascript" src="Auth.js"></script>
<script type="text/javascript" src="Presidents.js"></script>
<script type="text/javascript">
var UsersName;
function init()
{
CheckLogin();
}

function Controller(UNIT)
{
switch (UNIT)
{
case "Table" :
ShowPresidents();
break;
case "Logout" :
Logout();
break;
case "Login" :
Login(arguments[1],arguments[2]); //Username and Password
break;
default :
LoginForm();
break;
}
}

function StartApp()
{
var loggedInDiv = document.getElementById("LoggedInDiv");
var logOutDiv = document.getElementById("LogoutDiv");
loggedInDiv.innerHTML = "Logged in as " + UsersName;
loggedInDiv.style.display="block";
logOutDiv.style.display="block";
Controller("Table");
StartAutoLogoutTimer();
AttachEvent(document.body,"click",StartAutoLogoutTimer);
}

function EndApp()
{
clearTimeout(AutoLogoutTimer);
var loggedInDiv = document.getElementById("LoggedInDiv");
var logOutDiv = document.getElementById("LogoutDiv");
loggedInDiv.innerHTML = "";
loggedInDiv.style.display="none";
logOutDiv.style.display="none";
Controller("LoginForm");
DetachEvent(document.body,"click",StartAutoLogoutTimer);
}
window.onload = init;
</script>
<link type="text/css" rel="stylesheet" href="Presidents.css"/>
</head>

<body>
<div id="LogoutDiv" style="display:none; float:right;">
<form>
<input type="button" onClick="Controller('Logout')" value="Logout"/>
</form>
</div>
<div id="LoggedInDiv" style="display:none; float:right; margin-
right:20px;"></div>
<form onsubmit="return false" id="OutputForm">One moment
please...</form>
</body>
</html>
Code Explanation

This page contains the basic HTML elements that will hold data returned from the server:

<body>
<div id="LogoutDiv" style="display:none; float:right;">
<form>
<input type="button" onclick="Controller('Logout')" value="Logout"/>
</form>
</div>
<div id="LoggedInDiv" style="display:none; float:right; margin-
right:20px;"></div>
<form onsubmit="return false" id="OutputForm">One moment
please...</form>
</body>

The "OutputForm" form will hold the login form or the table data, depending on whether
or not the user is logged in. This page also controls the flow of the application:

1. When the page loads, the init() function is called, which in turn
calls the CheckLogin() function, which is in the Auth.js library. It looks
like this:
2. function CheckLogin()
3. {
4. new Ajax.Request("Controller.jsp",
5. {
6. method: "get",
7. parameters: "req=LoggedIn",
8. onComplete: _results
9. });
10.
11. function _results(REQ)
12. {
13. if (REQ.responseText.indexOf("failed") == -1)
14. {
15. UsersName = REQ.responseText;
16. StartApp();
17. }
18. else
19. {
20. Controller("LoginForm");
21. }
22. }
}
It makes an Ajax request to Controller.jsp, which handles the assignment of tasks
based on the req parameter. In this case, it will redirect to Helpers/LoggedIn.jsp,
which returns the user's name if he's logged in and the text "failed" if he is not.
Based on the response, the callback function, _results(), calls StartApp() to start
the applicationor calls the Controller() function, passing in "LoginForm". Let's
first see what happens when the user is not logged in:

o The Controller() function handles task assignment on the


client:
o function Controller(UNIT)
o {
o switch (UNIT)
o {
o case "Table" :
o ShowPresidents();
o break;
o case "Logout" :
o Logout();
o break;
o case "Login" :
o Login(arguments[1],arguments[2]); //Username
and Password
o break;
o default :
o LoginForm();
o break;
o }
}

In this case, it calls the LoginForm() function, which is in the Auth.js


library. It uses an Ajax request to get the login form and then displays the
form and sets the onsubmit callback function:

function LoginForm()
{
new Ajax.Request("Controller.jsp",
{
method: "get",
parameters: "req=LoginForm",
onComplete: _results
});

function _results(REQ)
{
var loginForm = document.getElementById("OutputForm");
loginForm.innerHTML = REQ.responseText;
loginForm.onsubmit = function() {
Controller("Login",loginForm.Username.value,loginForm.Pa
ssword.value);
return false;
}
}
}
o When the user logs in, the Controller() function is called
again. This time it is passed "Login" as the request and two
additional values: the username and password. The Controller
function in turn calls the Login() function, passing in the two
additional arguments:
o case "Login" :
o Login(arguments[1],arguments[2]); //Username and
Password
break;

o The Login() function, which is in the Auth.js library, tries


to log the user in with an Ajax call. If it fails, it reports the error to
the user. If it succeeds, it starts the application by calling
StartApp().
23. Now the user is logged in. The StartApp() function:
o Shows the divs that hold the user's name and the logout

button:
o Calls Controller() and passes in "Table" to get the
Presidents table.
o Calls StartAutoLogoutTimer() to start the count down to
the autologout.
o Attaches a click event to the body. Every user click will
cause the autologout timer to be reset.
24. The StartAutoLogoutTimer() function (in the Auth.js library) is
relatively straightforward:
25. var AutoLogoutTimer = null;
26. function StartAutoLogoutTimer()
27. {
28. var sessionTime = 15;
29. clearTimeout(AutoLogoutTimer);
30. AutoLogoutTimer = setTimeout("Logout(true)",
sessionTime * 1000); //15 seconds
}

The trick is that it restarts the timer every time it is called. When the timer does
run out, it will call Logout() and pass true, indicating that this is an autologout
rather than a user-initiated logout.

31. The Logout() function uses an Ajax call to a file that hides the
page, ends the session and then calls the EndApp() function, which
reinitiates the page. If the AUTO flag is set to true, then it also pops up an
alert letting the user know he's been logged out. The code is shown below.
32. function Logout(AUTO)
33. {
34. document.getElementById("OutputForm").innerHTML = "";
35. new Ajax.Request("Controller.jsp",
36. {
37. method: "get",
38. parameters: "req=Logout",
39. onComplete: _results
40. });
41.
42. function _results(REQ)
43. {
44. EndApp();
45. if (AUTO)
46. {
47. alert("You have been logged out due to inactivity.");
48. }
49. }
}

We won't look at all the server-side code, but the controller is worth checking out.

Code Sample: MoreAjaxApps/Demos/Controller.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%
try
{
String req;
if (request.getParameter("req") != null)
{
req = request.getParameter("req");
}
else
{
req = "LoginForm";
}

if (req.equals("Table"))
{
response.sendRedirect("Helpers/PresidentsTable.jsp");
}
else if (req.equals("Login"))
{
String un = request.getParameter("username");
String pw = request.getParameter("password");
response.sendRedirect("Helpers/Login.jsp?username=" + un +
"&password=" + pw);
}
else if (req.equals("LoggedIn"))
{
response.sendRedirect("Helpers/LoggedIn.jsp");
}
else if (req.equals("Logout"))
{
response.sendRedirect("Helpers/Logout.jsp");
}
else //LoginForm
{
response.sendRedirect("Helpers/LoginForm.jsp");
}
}
catch (Exception e)
{
out.write(e.toString());
}
%>
Code Explanation

As you can see, this page simply checks the value of the URL parameter, req, and dishes
out the work to helper files. This makes the flow of the application easier to follow and
maintain.

Autocompletion
Developers have become very excited about "autocomplete" dropdowns since Google
Suggest beta came out. A screenshot is shown below.

Writing your own autocompletion scripts would be a difficult undertaking. And it's
unlikely to be worth your while, as there are many such scripts available for free. The
script.aculo.us library makes creating autocompleting text fields very easy and our demo

below makes use of it:

The code is shown below.

Code Sample: MoreAjaxApps/Demos/AutoComplete.html


<html>
<head>
<title>AutoComplete</title>
<link rel="stylesheet" type="text/css" href="AutoComplete.css">
<script type="text/javascript" src="../../prototype.js"></script>
<script type="text/javascript"
src="../../scriptaculous_src/scriptaculous.js"></script>
<script type="text/javascript">
function init()
{
new
Ajax.Autocompleter("President","PresidentOptions","AutoComplete.jsp");
}

window.onload = init;
</script>
</head>

<body>
<form>
<input autocomplete="off" type="text" size="40" name="President"
id="President" />
<div class="auto_complete" id="PresidentOptions" style="display:
none;"></div>
</form>
</body>
</html>

Code Sample: MoreAjaxApps/Demos/AutoComplete.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" import="java.sql.*"%>
<%
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn = DriverManager.getConnection("jdbc:odbc:Presidents");

String sName = "%" + request.getParameter("President") + "%";

String sql = "SELECT PresidentID, FirstName, LastName FROM Presidents


WHERE FirstName LIKE ? OR LastName LIKE ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, sName);
stmt.setString(2, sName);

rs = stmt.executeQuery();
out.write("<ul>");
while (rs.next())
{
out.write("<li>");
out.write(rs.getString("FirstName") + " " +
rs.getString("LastName"));
out.write("</li>");
}
out.write("</ul>");
}
catch(Exception e)
{
out.write("failed:" + e.toString());
}
finally
{
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
%>
Code Explanation

The HTML file simply has an form input element and a div for outputting the dropdown
options. We create the autocomplete with script.aculo.us's Ajax.Autocompleter() method,
which requires three arguments: the name of the input field, the name of the output div,
and the file to get the results from.

The server-side script simply returns the results as an unordered list. We format this list
with CSS, which is in the associated AutoComplete.css file.

More Ajax Applications Conclusion


In this lesson of the Ajax tutorial, you have learned to apply some additional Ajax
techniques you have learned.
To continue to learn Ajax go to the top of this page and click on the next lesson in this
Ajax Tutorial's Table of Contents.
Ajax Tutorial (Asynchronous Javascript And XML)
Creating client-side dynamic web pages

• Brief history
• Why to use Ajax?
• What is Ajax, in depth?
• How does it works?
• Ajax and DHTML
• The XMLHttpRequest class
• Building a request, step by step
1. Create an instance
2. Wait
3. Send the request
• Examples
1. Get a text
2. Get from XML
3. Write to body
4. Post a text
• Using an external file
• How to build an Ajax website?
• Drawbacks
• Specifications
• Resources

Brief history

Ajax is only a name given to a set of tools that were previously existing.
The main part is XMLHttpRequest, a class usable in JavaScript , that was implemented into
Internet Explorer since the 4.0 version.
The same concept was named XMLHTTP some times, before the Ajax name becomes commonly
used.
The use of XMLHttpRequest in 2005 by Google, in Gmail and GoogleMaps has contributed to the
success of this format. But this is the name Ajax itself that made the technology so popular.

Why to use Ajax?

Mainly to build a fast, dynamic website, but also to save resources.


For improving sharing of resources, it is better to use the power of all the client computers
rather than just an unique server and network. Ajax allows to perform processing on client
computer (in JavaScript) with data taken from the server.
The processing of web page formerly was only server-side, using web services or PHP scripts,
before the whole page was sent within the network.
But Ajax can selectively modify a part of a page displayed by the browser, and update it
without the need to reload the whole document with all images, menus, etc...
For example, fields of forms, choices of user, may be processed and the result displayed
immediately into the same page.
What is Ajax in depth?

Ajax is a set of technologies, supported by a web browser, including these elements:

• HTML and CSS for presenting.


• JavaScript (ECMAScript) for local processing, and DOM (Document Object
Model) to access data inside the page or to access elements of XML file read on the
server (with the getElementByTagName method for example)...
• The XMLHttpRequest class read or send data on the server asynchronously.

optionally...

• The DomParser class may be used


• PHP or another scripting language may be used on the server.
• XML and XSLT to process the data if returned in XML form.
• SOAP may be used to dialog with the server.

The "Asynchronous" word, means that the response of the server while be processed when
available, without to wait and to freeze the display of the page.

How does it works?

Ajax uses a programming model with display and events. These events are user actions, they
call functions associated to elements of the web page.
Interactivity is achieved with forms and buttons. DOM allows to link elements of the page with
actions and also to extract data from XML files provided by the server.
To get data on the server, XMLHttpRequest provides two methods:
- open: create a connection.
- send: send a request to the server.
Data furnished by the server will be found in the attributes of the XMLHttpRequest object:
- responseXml for an XML file or
- responseText for a plain text.

Take note that a new XMLHttpRequest object has to be created for each new file to load.

We have to wait for the data to be available to process it, and in this purpose, the state of
availability of data is given by the readyState attribute of XMLHttpRequest.

States of readyState follow (only the last one is really useful):


0: not initialized.
1: connection established.
2: request received.
3: answer in process.
4: finished.

Ajax and DHTML

DHTML has same purpose and is also, as Ajax, a set of standards:


- HTML,
- CSS,
- JavaScript.
DHTML allows to change the display of the page from user commands or from text typed by the
user.
Ajax allows also to send requests asynchronously and load data from the server.

The XMLHttpRequest class

Allows to interact with the servers, thanks to its methods and attributes.

Attributes

readyState the code successively changes value from 0 to 4 that means for "ready".
200 is OK
status
404 if the page is not found.
responseText holds loaded data as a string of characters.
responseXml holds an XML loaded file, DOM's method allows to extract data.
property that takes a function as value that is invoked when the
onreadystatechange
readystatechange event is dispatched.

Methods

mode: type of request, GET or POST


url: the location of the file, with a path.
open(mode, url, boolean)
boolean: true (asynchronous) / false (synchronous).
optionally, a login and a password may be added to arguments.
send("string") null for a GET command.

Building a request, step by step

First step: create an instance


This is just a classical instance of class, but two options must be tried, for browser
compatibility.

if (window.XMLHttpRequest) // Object of the current windows


{
xhr = new XMLHttpRequest(); // Firefox, Safari, ...
}
else
if (window.ActiveXObject) // ActiveX version
{
xhr = new ActiveXObject("Microsoft.XMLHTTP"); // Internet Explorer
}

or exceptions may be used instead:

try {
xhr = new ActiveXObject("Microsoft.XMLHTTP"); // Trying Internet Explorer
}
catch(e) // Failed
{
xhr = new XMLHttpRequest()
}
Second step: wait for the response
The response and further processing are included in a function and the return of the function
will be assigned to the onreadystatechange attribute of the object previously created.

xhr.onreadystatechange = function() { // instructions to process the


response };
if (xhr.readyState == 4)
{
// Received, OK
} else
{
// Wait...
}

Third step: make the request itself


Two methods of XMLHttpRequest are used:
- open: command GET or POST, URL of the document, true for asynchronous.
- send: with POST only, the data to send to the server.
The request below read a document on the server.

xhr.open('GET', 'http://www.xul.fr/somefile.xml', true);


xhr.send(null);

Examples
Get a text
<html>
<head>
<script>
function submitForm()
{
var xhr;
try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
catch (e)
{
try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
catch (e2)
{
try { xhr = new XMLHttpRequest(); }
catch (e3) { xhr = false; }
}
}

xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
document.ajax.dyn="Received:" + xhr.responseText;
else
document.ajax.dyn="Error code " + xhr.status;
}
};

xhr.open(GET, "data.txt", true);


xhr.send(null);
}
</script>
</head>

<body>
<FORM method="POST" name="ajax" action="">
<INPUT type="BUTTON" value="Submit" ONCLICK="submitForm()">
<INPUT type="text" name="dyn" value="">
</FORM>
</body>
</html>
Syntax of form using Ajax

View a demo of the example in action.

Download the source.

Comments on the code:


new ActiveXObject(Microsoft.XMLHTTP)
This constructor is for Internet Explorer.

new XMLHttpRequest()
This constructor is for any other browser including Firefox.

http.onreadystatechange
An anonymous function is assigned to the event indicator.

http.readyState == 4
The 4 state means for the response is ready and sent by the server.

http.status == 200
This status means ok, otherwise some error code is returned, 404 for example.

http.open( "POST", "data.xml", true);


POST or GET
URL of the script to execute.
true for asynchronous (false for synchronous).

http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
This is for POST only.

http.send(document.getElementById("TYPEDTEXT").value);
Send data to the server. Data comes from the "TYPEDTEXT" variable filled throught the form
by the user.

Get from XML

To get data from an XML file we have just to replace this line:

document.ajax.dyn="Received:" + xhr.responseText;

by this code:

var doc = xhr.responseXML; // Assign the XML file to a var


var element = doc.getElementsByTagName('root').item(0); // Read the first
element
document.ajax.dyn.value= element.firstChild.data; // Assign the content to
the form

View a demo of the get from XML example in action.

Write to body

In this demo, the text read is put into the body of the page, and not into a textfield. The code
below replaces the textfield form object and the second part replaces the assignment into the
JavaScript function.

<div id="zone">
... some text to replace ...
</div>
document.getElementById("zone").innerHTML = "Received:" + xhr.responseText;

Post a text

In this demo, a text is sent to the server and is written into a file. The call to the "open"
method changes, the argument is POST, the url is the name of a file or script that receives the
data sent, and that must process it. And the "send" method has now a value as argument that is
a string of parameters.

xhr.open("POST", "ajax-post-text.php", true);


xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(data);

The parameter of the send method is in format of the HTML POST method. When several values
are sent, they are separated by the ampersand symbol:

var data = "file=" + url + "&content=" + content;


The "file" parameter is the name of a file created to store the content. The filename must be
checked by the server to prevent any other file to be modified.

Using an external file

It is simpler to include a JavaScript file. This line will be included into the head section of the
HTML page:

<script src="ajax.js" type="text/javascript"></script>

And the function is called with this statement:

var xhr = createXHR();

View the script in the ajax.js file.

How to build an Ajax website?

You need for some wrapper. A short list of frameworks is provided below.
Your JavaScript program, integrated into a web page, sends request to the server to load files
for rebuilding of pages. The received documents are processed with Dom's methods or XML
parsers and the data are used to update the pages.

Drawbacks of Ajax

- If JavaScript is not activated, Ajax can't works. The user must be asked to set JavaScript from
within options of the browser, with the "noscript" tag.
- Since data to display are loaded dynamically, they are not part of the page, and the keywords
inside are not used by search engines.
- The asynchronous mode may change the page with delays (when the processing on the server
take some times), this may be disturbing.
- The back button may be deactivated (this is not the case in examples provided here). This
may be overcomed.

Specifications

Ajax is based on these specifications:


- XML 1, HTML 4, DOM 2, CSS 2 from W3C
- ECMAScript 1.5. Standard for JavaScript from ECMA.
- W3C draft specification for XMLHttpRequest.
- HTTP 1.1. Status codes: 404 etc

The XMLHttpRequest Object


Summary of the specification by W3C, and usage

This object is used by JavaScript to exchange data with the server, in plain text, XML or JSON
format. The XML format is automatically parsed by the object at loading and accessible by
DOM's methods. JSON files are parsed by the eval() JavaScript command.

• Brief history
• Description
• Attributes
• Methods
• How to use XMLHttpRequest
• Caching problem
• The HTML format
• Demos
• Specification
• Resources

Brief history
XMLHttpRequest, was first implemented by Internet Explorer since the 4.0 version.
The same concept was named XMLHTTP some times, before the Ajax name becomes commonly
used.
The use of XMLHttpRequest in 2005 by Google, in Gmail and GoogleMaps has contributed to the
success of this technology.

Description

This is a class that is recognized by all current browsers, and by the JavaScript client side
programming language.
For each request to the server, a new instance is created by a call to the constructor.
The open method starts the connection, in read or write mode, to receive data from the server
or send it. It will be processed by the server with a server side language as PHP, Java, etc...
The connection takes several successive states that are assigned to the readyState attribute of
the object.
When the final state is reached, the data may be found in another attribute. It may be a plain
text or an XML document. The JSON format is loaded as plain text and parsed by JavaScript.
More details on the use of the class in the Ajax tutorial.

Attributes

The purpose of attributes of the class is to be assigned the status of the connection, and to
hold data.

The code successively changes value until the server is ready, from 0 to 4 .

• 0 Not initialized
• 1 Open
unsigned short readyState
• 2 Sent
• 3 Received

• 4 Loaded
200 is ok
unsigned short status
404 if the page is not found.
DOMString statusText Holds the label of the status, corresponding to the status code.
Holds loaded data as a string of characters. It is completely filled when the
DOMString responseText
status is 4.
DOMDocument Holds an XML loaded file, and DOM's methods allow to extract data. It is
responseXml filled only when the code is 4 and null otherwise.
EventListener
Invoked when readyState is assigned.
onreadystatechange

Methods

Apart the constructor, the class has two main methods, open to create a session and designate
the distant file, and send to move data to the server.

abort() Resets the object and stops any activity created by the object.
getAllResponseHeaders() Return all headers into a string, separated by CR and LF codes.
Return the header of data received, after the last request. Several
getResponseHeader(DOMString)
headers should be separated by a comma plus a space.
open(mode, url, boolean [, mode: type of request, GET, POST, HEAD or other http methods.
url: the location of the file, with a path.
login, password]) boolean: true (asynchronous) / false (synchronous).
optionally, a login and a password as additional arguments.
null or empty with a GET command, a string otherwise.
send("string") Raises a DOMException (INVALID_STATE_ERR) if the readyState code is
not 1.
Arguments are the name of the header and the value. Several values
setRequestHeader(DOMString, may be successively sent.
DomString) Raises a DOMException (INVALID_STATE_ERR) if the readyState code is
not 1.

How to use XMLHttpRequest


The class is a part of ECMAScript (JavaScript) and used as any other class of the language, but
there are several constructors according to the browser. Here is a complete code to open an
Ajax session, by creating a new XMLHttpRequest object and loading some data.
The code may be tested with several demos on the Ajax tutorial and in the Ajax sub-domain.

<html>
<head>
<script language="JavaScript>

function submitForm()
{
var xhr=null;

try
{
xhr = new XMLHttpRequest();
} catch(e)
{
try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e2)
{
try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e) {}
}
}

xhr.onreadystatechange = function()
{
document.ajax.dyn.value="Wait server...";
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
document.ajax.dyn.value="Received:" + xhr.responseText;
}
else
{
document.ajax.dyn.value="Error: returned status code " +
xhr.status + " " + xhr.statusText;
}
}
};

xhr.open("GET", "data.xml", true);


xhr.send(null);
}
</script>
</head>

<body>
<FORM method="POST" name="ajax" action="">
<INPUT type="submit" value="Submit" ONCLICK="submitForm()">
<INPUT type="text" name="dyn" value="">
</FORM>
</body>
</html>

Caching problem

Memory cache does not work properly with the object. Often, the file loaded by the GET
method is not the last version, but an older version taken from the memory buffer. If the file is
not too big, this can be overcomed easily by adding a parameter to the command. Replace:

xhr.open("GET", "data.xml", true);

by

xhr.open("GET", "data.xml?nocache=" + Math.random(), true);

The HTML format

We can load XML files, can we load also HTML or XHTML files? Actually, this is planned for the
next specification of the XMLHttpRequest object as it is planned to access cross-domains files.
It is planned that, in this case, the text/html mime type will be used, while the text/xml type
is used for XML documents, in the content type header.
For now, a replacing solution exists, the pseudo responseHTML attribute, that is given on this
site.

Demos
This small demo makes use of the HEAD method to read the headers of a web page.
Another demo shows the successive states of readyState.
More demos in the resource section below.

Specification

• W3C Working Draft specification for XMLHttpRequest.

Ajax Frameworks
The best technology to build dynamic web pages is Ajax. JavaScript code embedded into the
HTML page is used to send requests to the server. At the server side, some processing is
required to handle them, find the info or store the data. To do that, we need for a specialized
framework. The framework has always a JavaScript part, and sometimes a server side part in
another scripting language. A lot of them exist in various programming languages, in all
environments around, but we retain here only the most widely used.
Summary

• Why a framework?
• Features of an Ajax framework
• JavaScript libraries
• PHP frameworks
• Java frameworks
• .NET frameworks
• ColdFusion frameworks
• Ajax and XUL
• Beyond Ajax
• Resources

Why a framework?

Actually, this framework is the Ajax engine described by J. J. Garrett and intended to suppress
waiting for the user when accessing the server.
The framework provides classical, cross-browser functions to use the XMLHttpRequest object.
But a framework may goes beyond that, and allow to build "rich web applications", applications
with a graphical user interface and other features of desktop software that run through a
browser, while exchanging data with a remote server.

Features of an Ajax framework

Any Ajax framework is able to communicate with the server, and thus, to read data or to send
it data or commands. In the last case a server-side script is required.
The frameworks often add components that make use of the asynchronous communication with
the server.
The classical examples are buttons, tabbed panels, grids, listboxs and other such widgets.
A more innovative example, the "boxes", are more and more often implemented, and Lightbox
and Slimbox are two of them. There are image galleries that place them side by side on the
screen and that are making use of Ajax to display them instantanously .

Framework may be server-driven also, and in this case, component are created on the server
with a scripting language such as PHP, and sent to the browser. Ajax is used to transmit user
actions to the server part, and to handle the results.

The ability to work offline as it is offered by Google Gears, may be added to the Ajax
framework as well.

JavaScript libraries

Many Ajax frameworks and libraries rely solely upon JavaScript and contain no server
components and therefore server technology dependencies.
Most of them use XML as data format, and sometime JSON, another textual format.
A JavaScript library is loaded with just a tag, as this:

<script src="prototype.js" type="text/javascript></script>


This tag includes the "prototype" library into the page and its function become usable by the
browser, in this page.
Such Ajax libraries and frameworks include:

• Prototype.
Is the base of several other frameworks including that of Yahoo. Its goal seems to be
in reducing the size of Ajax Code.
• Script Aculo.
Add more features to prototype.
• Rico.
Based also on prototype, add special effects to HTML pages.
• Jquery.
JavaScript library with Ajax support. It is equivalent to Script Aculo and uses less
resources.
• Mootools.
Another toolkit as JQuery, includes graphical effects.
• Dojo Toolkit.
Uses packages with a mechanism to load them together along with the page. It can
build reusable components and widgets, a lot of them is provided on the site. It
allows to manipulate the DOM more easily, and to make graphical effects.
• Qooxdoo.
Includes advanced cross-browser layout managers and an advanced build system for
graphical user interfaces similar to that of desktop software. Widgets are provided
with the function to use them from the keyboard or the mouse. Third parties provide
PHP or Java code to process data with XMLHttpRequest.
• Yahoo UI.
Library from the Yahoo search engine. Includes CSS resources.
• Anaa.
A simple library for GET and POST with callbacks. Implements responseHTML, the
A.E.P. extension.

PHP frameworks

On the server side, the programmer may use PHP functions to process requests from the
browser. PHP allows to deal with database, search data, build pages or parts of page and
publish the page or return data to the XMLHttpRequest object. PHP 5 specifically, thanks to its
SimpleXML class, is able to create XML files that may be returned to the object. But all these
tasks require special functions to write... however the work is already done in some free open
source frameworks.

• AjaxAC.
Small PHP library.
• Xajax.
More sophisticated, is made of a JavaScript library and PHP classes, to help in using
other PHP functions written by you. Uses only the XML format, on the server side.
• Tiny Ajax.
A small PHP 5 class.

Java frameworks

Java is the programming language that is the more often used to build web services.
A Java framework permit to use Java web services interactively with a web page.
The more commonly used are:
• DWR (Direct Web Remoting).
Allows to use Java functions as if they are part of the browser, from HTML code,
thanks to its interface. A JavaScript part is used to update the page and another to
get data with servlets.
The technique is in generating in real time Java code from JavaScript code, send it to
the server and run it.
• Google Web Toolkit.
A toolbox to develop Java applications, that are then compiled into JavaScript code,
and this code processes the HTML page through DOM methods.

Legacy Java software for the web now is moving to Ajax. JavaServer Faces now includes Ajax
features. ThinWire takes a unique approach in that the application is written as if it was a
desktop software. All the logic executes on the server, the framework encapsulates the web
rendering and communication layers.

.NET frameworks

• Microsoft Ajax Library (formerly ATLAS) is made of a client side part: Microsoft
AJAX Library, and a server side part: ASP.NET 2.0 Ajax Extensions. But a component
library is also provided with graphical widgets: ASP.NET Ajax Control Toolkit.
• Ajax.NET Professional "serializes" (converts and stores) .NET data to the JSON
format.

ColdFusion frameworks

Libraries include:

• AjaxCFC. An object oriented framework that provides developers seamless


integration between JavaScript and ColdFusion, and built-in security and debugging
functions.
• CFAjax. Implements Ajax in such a way that ColdFusion method calls on the
server gets executed using JavaScript a la Ajax.

Ajax and XUL

Ajax make use of the JavaScript programming language, and XUL embeds also JavaScript into
XML to define the interaction with the graphical user interface. The two systems work on the
Firefox browser. The first one allows to communicate with the server from a remote web page,
the second one displays an interface either in a local computer or through the net, with the
same browser.
The main difference is in the use of Canvas (HTML tag) to extend Ajax and to extend XUL,
XPCom and XBL.

• ZK.
Framework designed for allowing Ajax and XUL to communicate.

Beyond Ajax

Some current developments will reinforce again the importance of Ajax by providing standard
for RIA (Rich Internet Applications), mainly HTML 5 qui extends HTML with Web applications
features and Google Gears that allows a Web application to run offline.
Ajax Extensible Page
Ajax without programming

The A.E.P. JavaScript library allows to create dynamic pages with a content expanded at user
request, either locally at a click on a sign, or a work or a phrase, or globally at a clic on the
"expand" button or text.
A.E.P. is an innovation of the Web 2.0 that changes the way Web sites are built and used.

Expand the content Collapse the content

Benefits of extensible pages

- Two-levels articles. A same page may be read by experienced reader, without to be annoyed
with details that are obvious for them, et it may be read also by beginners which can get more
info when needed.
- Avoiding go and back. Requested data being inserted into the current page, we have just to
read and scroll to continue.
- And a lot more...

Using

The "expand" and "collapse" links on a modern Web page should stay besides the "print" link
that allows to display a printable version of the page.
Actually, the framework can be used also to create this printable version.
More details about using A.E.P on the manual...

The extensible logo

When you choose to use textual links, that are not as visible as buttons, it is better to inform
your visitors the page is extensible with this logo:

and in all case you can also inform your visitors to what extensible page is by a link on this
page:

<a href="http://ajax.xul.fr/extensible/" target="_top"> <img


src="extensible.jpg"> </a>

Manual

Making a page extensible is very simple:


1) put a replacing text into a <div> and give it an identifier or into a text file.
2) put a text to replace into a <span>, give it an identifier and assign to a "name" attribute the
identifier of the replacing text, or to a "src" attribute the filename.
3) Call a JavaScript function with the onclick event.

The manual is aimed at webmasters and describes all functions of the A.E.P. library

• HTML version.
• A PDF printable version may be saved with Star Office in the Google Pack.

Compatibility

The framework has been tested under:


- Internet Explorer.
- Firefox.
- Opera.
Details.

Demonstration

• Demo of the combination summarize + quietVerbose.

Download

The zip archive holds the extensible.js library, a PDF version of the manual and some demos.

• Download AEP. Version.

Last changes.

Resources

• A JavaScript tutorial to use the library with a single button or textual command.
Ajax Demos
Several demos of Ajax and the XMLHttpRequest object. Each demo is a HTML page, that holds
the JavaScript code and the HTML form used to interact with the script.
All the demos use an external JavaScript file, ajax.js that creates an instance of the object,
and assigns it to the xhr variable.
You are free to use the code of these demos as template for pages of your own website (see
licence at bottom).

Get a file

Read a text file from the server and display the content on the current page.
This is a minimal script that makes use of the GET method and checks only for the value of
readyState, and not the status.
This very simple code can work locally on a desktop.

Values of readyState

This property holds successive values of the readyState property, starting from 1, and ending to
4 when the exchange with the server is completed. This demo displays the values and helps to
understand how the XMLHttpRequest object works.

File exists

Simple demo to check if a file exists.


Form and XML

Fill a form with data taken from an XML document.

Reading an HTML page

This demo creates the responseHTML-like attribute, as the responseText and responseXML
attributes of XMLHttpRequest. It is made of a JavaScript function and a tag. To add this new
feature to a web page, copy the three lines of code from the demo file, and past them into the
page that has to read the content of another HTML page.
Works remotely or locally, and with any browser.

Scaling images under the mouse

Script to show how to manage a gallery of thumbnails with a function to display image in full
size, when the mouse is moved over a thumbnail.
Ajax is used for loading the full size images asynchronously after the loading of the page.

Sequence of requests
Vous can have a dialogue with a program on the server, by chaining Ajax requests, with the
POST method to send data to the server and GET to retrieve the results found by the remote
program. The demo shows how to overcome the traps of the asynchronous mode.

Potrebbero piacerti anche