Tuesday, July 14, 2009

AJAX and PHP Building Responsive Web Applications by Cristian Darie, Bogdan Brinzarea Chapter 2

Client-Side Techniques with
Smarter JavaScript

It is said that one picture is worth a thousand words. And so is a well-written piece of code, we would say. You will get plenty of both, while building the foundations for your future AJAX-enabled applications, in this chapter and the next.

Hopefully, the first chapter has developed your interest in AJAX well enough that you will endure a second chapter with lots of theory to be learned. On the other hand, if you found the first
exercise too challenging, be assured that this time we will advance a bit slower. We will learn the theory in parts by going through many short examples. In this chapter, we will meet client AJAX technologies, which include:

• JavaScript
• The JavaScript DOM
• Cascading Style Sheets (CSS)
• The XMLHttpRequest object
• Extensible Markup Language (XML)

You will learn how to make these components work together smoothly, and form a strong foundation for your future AJAX applications. You will see how to implement efficient error handling techniques, and how to write code efficiently. Chapter 3 will complete the foundations by presenting the techniques and technologies that you use on the server; in our case, PHP, MySQL, and others.

To be a good AJAX developer you need to know very well how its ingredients work separately, and then master how to make them work together. In this book, we assume you have some experience with at least a part of these technologies.

Depending on your experience level, take some time—before, while, or after reading Chapter 2 or Chapter 3, to have a look at Appendix B on http://ajaxphp.packtpub.com, which shows you a number of tools that make a programmer's life much easier. Don't skip it, because it's important, as having the right tools and using them efficiently can make a very big difference.

You can see all the example applications from this book online at http://ajaxphp.packtpub.com/.

JavaScript and the Document Object Model
As mentioned in Chapter 1, JavaScript is the heart of AJAX. JavaScript has a similar syntax to the good old C language. JavaScript is a parsed language (not compiled), and it has some Object-Oriented Programming (OOP) capabilities. JavaScript wasn't meant for building large powerful applications, but for writing simple scripts to implement (or complement) a web application's client-side functionality (however, new trends are tending to transform JavaScript into an enterprise-class language—it remains to be seen how far this will go).

JavaScript is fully supported by the vast majority of web browsers. Although it is possible to execute JavaScript scripts by themselves, they are usually loaded on the client browsers together with HTML code that needs their functionality. The fact that the entire JavaScript code must arrive unaltered at the client is a strength and weakness at the same time, and you need to consider these aspects before deciding upon a framework for your web solution. You can find very good introductions to JavaScript at the following web links:

• http://www.echoecho.com/javascript.htm
• http://www.devlearn.com/javascript/jsvars.html
• http://www.w3schools.com/js/default.asp

Part of JavaScript's power on the client resides in its ability to manipulate the parent HTML document, and it does that through the DOM interface. The DOM is available with a multitude of languages and technologies, including JavaScript, Java, PHP, C#, C++, and so on. In this chapter, you will see how to use the DOM with both JavaScript and PHP. The DOM has the ability to manipulate (create, modify, parse, search, etc.) XML-like documents, HTML included.

On the client side, you will use the DOM and JavaScript to:

• Manipulate the HTML page while you are working on it
• Read and parse XML documents received from the server
• Create new XML documents

On the server side, you can use the DOM and PHP to:

• Compose XML documents, usually for sending them to the client
• Read XML documents received from various sources

Two good introductions to DOM can be found at http://www.quirksmode.org/dom/intro.html and http://www.javascriptkit.com/javatutors/dom.shtml. Play a nice DOM game here: http://www.topxml.com/learning/games/b/default.asp. A comprehensive reference of the JavaScript DOM can be found at http://krook.org/jsdom/. The Mozilla reference for the JavaScript DOM is available at http://www.mozilla.org/docs/dom/reference/javascript.html.

In the first example of this chapter, you will use the DOM from JavaScript to manipulate the HTML document. When adding JavaScript code to an HTML file, one option is to write the JavaScript code in a <script> element within the <body> element. Take the following HTML file for example, which executes some simple JavaScript code when loaded. Notice the document object, which is a default object in JavaScript that interacts with the DOM of the HTML page. Here we use its write method to add content to the page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: JavaScript and DOM</title>
<script type="text/javascript">
// declaring new variables var date = new Date();
var hour = date.getHours();
// demonstrating the if statement if (hour >= 22 || hour <= 5)
document.write("You should go to sleep.");
else
document.write("Hello, world!");
</script>
</head>
<body>
</body>
</html>

The document.write commands generate output that is added to the <body> element of the page when the script executes. The content that you generate becomes part of the HTML code of the page, so you can add HTML tags in there if you want.

We advise you try to write well-formed and valid HTML code when possible. Writing code compliant to HTML format maximizes the chances that your pages will work fine with most existing and future web browsers. A useful article about following web standards can be found at http://www.w3.org/QA/2002/04/Web-Quality. You can find a useful explanation of the DOCTYPE element at http://www.alistapart.com/stories/doctype/. The debate on standards seems to
be an endless one, with one group of people being very passionate about strictly following the standards, while others are just interested in their pages looking good on a certain set of browsers. The examples in this book contain valid HTML code, with the exception of a few cases where we
broke the rules a little bit in order to make the code easier to understand. A real fact is that very
few online websites follow the standards, for various reasons.

You will usually prefer to write the JavaScript code in a separate .js file that is referenced from the .html file. This allows you to keep the HTML code clean and have all the JavaScript code organized in a single place. You can reference a JavaScript file in HTML code by adding a child element called <script> to the <head> element, like this:

<html>
<head>
<script type="text/javascript" src="file.js"></script>
</head>
</html>

Even if you don't have any code between <script> and </script> tags, don't be tempted to use the short form <script type="text/javascript" src="file.js" />

This causes problems with Internet Explorer 6, which doesn't load the JavaScript page.

Let's do a short exercise.

Time for Action—Playing with JavaScript and the DOM
1. Create a folder called foundations in your ajax folder. This folder will be used for all the examples in this chapter and the next chapter.
2. In the foundations folder, create a subfolder called jsdom.
3. In the jsdom folder, add a file called jsdom.html, with the following code in it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: JavaScript and DOM</title>
<script type="text/javascript" src="jsdom.js"></script>
</head>
<body>
I love you!
</body>
</html>

4. In the same folder create a file called jsdom.js, and write this code in the file:
// declaring new variables var date = new Date();
var hour = date.getHours();
// demonstrating the if statement
if (hour >= 22 || hour <= 5)
document.write("Goodnight, world!");
else
document.write("Hello, world!");

5. Load http://localhost/ajax/foundations/jsdom/jsdom.html in your web browser, and assuming it's not late enough, expect to see the message as shown in Figure 2.1 (if it's past 10 PM, the message would be a bit different, but equally romantic).

Figure 2.1: The Hello World Example with JavaScript and the DOM

What Just Happened?
The code is very simple indeed and hence it doesn't need too many explanations. Here are the main ideas you need to understand:

• Because there is no server-side script involved (such as PHP code), you can load the file in your web browser directly from the disk, locally, instead of accessing it through an HTTP web server. If you execute the file directly from disk, a web browser would likely open it automatically using a local address such as file:///C:/Apache2/htdocs/ajax/foundations/jsdom/jsdom.html.
• When loading an HTML page with JavaScript code from a local location (file://) rather than through a web server (http://), Internet Explorer may warn you that you're about to execute code with high privileges (more on security in Chapter 3).
• JavaScript doesn't require you to declare the variables, so in theory you can avoid the
var keywords. This isn't a recommended practice though.
• The JavaScript script executes automatically when you load the HTML file. You can, however, group the code in JavaScript functions, which only execute when called explicitly.
• The JavaScript code is executed before parsing the other HTML code, so its output is displayed before the HTML output. Notice that "Hello World!"appears before
"I love you!".

One of the problems of the presented code is that you have no control in the JavaScript code over where the output should be displayed. As it is, the JavaScript output appears first, and the contents of the <body> element come next. Needless to say, this scenario isn't relevant even to the simplest of applications.

Except for the most simple of cases, having just JavaScript code that executes unconditionally when the HTML page loads is not enough. You will usually want to have more control over when and how portions of JavaScript code execute, and the most typical scenario is when you use JavaScript functions, and execute these functions when certain events (such as clicking a button) on the HTML page are triggered.

JavaScript Events and the DOM
In the next exercise, we will create an HTML structure from JavaScript code. When preparing to build a web page that has dynamically generated parts, you first need to create its template (which contains the static parts), and use placeholders for the dynamic parts. The placeholders must be uniquely identifiable HTML elements (elements with the ID attribute set). So far we have used the
<div> element as placeholder, but you will meet more examples over the course of this book. Take a look at the following HTML document:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: More JavaScript and DOM</title>
</head>
<body>
Hello Dude! Here's a cool list of colors for you:
<br/>
<ul>
<li>Black</li>

<li>Orange</li>
<li>Pink</li>
</ul>
</body>
</html>

Suppose that you want to have everything in the <ul> element generated dynamically. The typical way to do this in an AJAX application is to place a named, empty <div> element in the place where you want something to be generated dynamically:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: More JavaScript and DOM</title>
</head>
<body>
Hello Dude! Here's a cool list of colors for you:
<br/>
<div id="myDivElement"/>
</body>
</html>

In this example we will use the <div> element to populate the HTML document from JavaScript code, but keep in mind that you're free to assign ids to all kinds of HTML elements. When adding the <ul> element to the <div> element, after the JavaScript code executes, you will end up with
the following HTML structure:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>Colors</title>
</head>
<body>
Hello Dude! Here's a cool list of colors for you:
<br/>
<div id="myDivElement">
<ul>
<li>Black</li>
<li>Orange</li>
<li>Pink</li>
</ul>
</div>
</body>
</html>

Your goals for the next exercise are:

• Access the named <div> element programmatically from the JavaScript function.
• Having the JavaScript code execute after the HTML template is loaded, so you can access the <div> element (no HTML elements are accessible from JavaScript code that executes referenced from the <head> element). You will do that by calling JavaScript code from the <body> element's onload event.
• Group the JavaScript code in a function for easier code handling.

Time for Action—Using JavaScript Events and the DOM
1. In the foundations folder that you created in the previous exercise, create a new folder called morejsdom.
2. In the morejsdom folder, create a file called morejsdom.html, and add the following code to it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: More JavaScript and DOM</title>
<script type="text/javascript" src="morejsdom.js"></script>
</head>
<body onload="process()">
Hello Dude! Here's a cool list of colors for you:
<br />
<div id="myDivElement" />
</body>
</html>

3. Add a new file called morejsdom.js, with the following contents:
function process()
{
// Create the HTML code var string;
string = "<ul>"
+ "<li>Black</li>"
+ "<li>Orange</li>"
+ "<li>Pink</li>"
+ "</ul>";
// obtain a reference to the <div> element on the page
myDiv = document.getElementById("myDivElement");
// add content to the <div> element myDiv.innerHTML = string;
}

4. Load morejsdom.html in a web browser. You should see a window like the one in Figure 2.2:

Figure 2.2: Your Little HTML Page in Action

What Just Happened?
The code is pretty simple. In the HTML code, the important details are highlighted in the following code snippet:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: More JavaScript and DOM</title>
<script type="text/javascript" src="morejsdom.js"></script>
</head>
<body onload="process()">
Hello Dude! Here's a cool list of colors for you:
<br/>
<div id="myDivElement" />
</body>
</html>

Everything starts by referencing the JavaScript source file using the <script> element. The JavaScript file contains a function called process(), which is used as an event-handler function for the body's onload event. The onload event fires after the HTML file is fully loaded, so when the process() function executes, it has access to the whole HTML structure. Your process() function starts by creating the HTML code you want to add to the div element:

function process()
{
// Create the HTML code var string;
string = "<ul>"
+ "<li>Black</li>"
+ "<li>Orange</li>"
+ "<li>Pink</li>"
+ "</ul>";

Next, you obtain a reference to myDivElement, using the getElementById function of the document object. Remember that document is a default object in JavaScript, referencing the body of your HTML document.

// obtain a reference to the <div> element on the page myDiv = document.getElementById("myDivElement");

Note that JavaScript allows you to use either single quotes or double quotes for string variables. The previous line of code can be successfully written like this:

myDiv = document.getElementById('myDivElement');

In the case of JavaScript, both choices are equally good, as long as you are consistent about using only one of them. If you use both notations in the same script you risk ending up with parse errors. In this book, we will use double quotes in JavaScript programs.

Finally, you populate myDivElement by adding the HTML code you built in the string variable:

// add content to the <div> element myDiv.innerHTML = string;
}

In this example, you have used the innerHTML property of the DOM to add the composed HTML
to your document.

Even More DOM
In the previous exercise, you have created the list of elements by joining strings to compose a simple HTML structure. The same HTML structure can be built programmatically using the DOM. In the next exercise, you will generate this content programmatically:

<div id="myDivElement">
Hello Dude! Here's a cool list of colors for you:
<br/>
<ul>
<li>Black</li>
<li>Orange</li>
<li>Pink</li>
</ul>
</div>

A DOM document is a hierarchical structure of elements, where each element can have one or more attributes. In this HTML fragment, the single element with an attribute is <div>, which has an attribute called id with the value myDivElement. The root node that you can access through the
document object is <body>. When implementing the above HTML document, you will end up with a structure such as the one in the figure below:

Figure 2.3: A Hierarchy of HTML Elements

In Figure 2.3, you see an HTML structure formed of <body>, <div>, <br>, <ul>, and <li> elements, and four text nodes ("Hello…", "Black", "Orange", "Pink"). In the next exercise, you will create this structure using the DOM functions createElement, createTextNode, and appendChild.

Time for Action—Even More DOM
1. In the foundations folder, create a subfolder called evenmorejsdom.
2. In the evenmorejsdom folder, create a file called evenmorejsdom.html, and add the following code to it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: Even More JavaScript and DOM</title>
<script type="text/javascript" src="evenmorejsdom.js"></script>

<body onload="process()">
<div id="myDivElement" />
</body>
</html>

3. Add a new file called evenmorejsdom.js, with the following contents:
function process()
{
// create the first text node
oHello = document.createTextNode
("Hello Dude! Here's a cool list of colors for you:");

// create the <ul> element
oUl = document.createElement("ul")

// create the first <ui> element and add a text node to it oLiBlack = document.createElement("li");
oBlack = document.createTextNode("Black");
oLiBlack.appendChild(oBlack);

// create the second <ui> element and add a text node to it oLiOrange = document.createElement("li");
oOrange = document.createTextNode("Orange");
oLiOrange.appendChild(oOrange);

// create the third <ui> element and add a text node to it oLiPink = document.createElement("li");
oPink = document.createTextNode("Pink");
oLiPink.appendChild(oPink);

// add the <ui> elements as children to the <ul> element oUl.appendChild(oLiBlack);
oUl.appendChild(oLiOrange);
oUl.appendChild(oLiPink);

// obtain a reference to the <div> element on the page myDiv = document.getElementById("myDivElement");

// add content to the <div> element myDiv.appendChild(oHello); myDiv.appendChild(oUl);
}

4. Load evenmoredom.html in a web browser. The result should look like Figure 2.4:

Figure 2.4: Even More JavaScript and DOM

What Just Happened?
Well, what just happened is exactly what happened after the previous exercise, but this time with much more code, as you can see by having a look at the process() function. Although there are many lines of code, the functionality is pretty simple. This suggests clearly enough that using the DOM to create HTML structures may not always be the best option. However, in certain circumstances it can actually make programming easier, for the following reasons:

• It's fairly easy to programmatically create dynamic HTML structures, such as building elements in for loops, because you're not concerned about text formatting but about building the structural elements.
• As a consequence, you don't need, for example, to manually add closing tags. When you add a 'ui' element, the DOM will take care to generate the <ui> tag and an associated closing </ui> tag for you.
• You can treat the nodes as if they were independent nodes, and decide later how to build the hierarchy. Again, the DOM takes care of the implementation details; you just need to tell it what you want.

JavaScript, DOM, and CSS
CSS (Cascading Style Sheets) is certainly a familiar term for you. CSS allows setting formatting options in a centralized document that is referenced from HTML files. If the job is done right, and CSS is used consistently in a website, CSS will allow you to make visual changes to the entire site (or parts of the site) with very little effort, just by editing the CSS file. There are many books and tutorials on CSS, including the free ones you can find at http://www.w3.org/Style/CSS/ and http://www.w3schools.com/css/default.asp. Although the article that invented the name AJAX (http://www.adaptivepath.com/publications/essays/archives/000385.php)
mentions CSS as one of the AJAX ingredients, technically CSS is not required to build successful dynamic web applications. However, its usage is highly recommended because of the significant benefits it brings.

We will do a simple exercise to demonstrate using CSS, and manipulating HTML elements' styles using the DOM. These are usual tasks you will do when building AJAX applications. In the following exercise, you will draw a nice table, and you will have two buttons named Set Style 1 and Set Style 2. These buttons will change the table's colors and appearance by just switching the current styles. See Figure 2.5 to get a feeling about what you're about to create.

Time for Action—Working with CSS and JavaScript
1. In the foundations folder, create a new subfolder called csstest.
2. In your newly created csstest folder, create a new file called csstest.html, with the following contents:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: CSS</title>
<script type="text/javascript" src="csstest.js"></script>
<link href="styles.css" type="text/css" rel="stylesheet"/>

<body>
<table id="table">
<tr>
<th id="tableHead"> Product Name
</th>
</tr>
<tr>
<td id="tableFirstLine"> Airplane
</td>
</tr>
<tr>
<td id="tableSecondLine">
Big car
</td>
</tr>
</table>
<br />
<input type="button" value="Set Style 1" onclick="setStyle1();" />
<input type="button" value="Set Style 2" onclick="setStyle2();" />
</body>
</html>

3. Create a file called csstest.js and write the following code in it:
// Change table style to style 1 function setStyle1()
{
// obtain references to HTML elements oTable = document.getElementById("table");
oTableHead = document.getElementById("tableHead"); oTableFirstLine = document.getElementById("tableFirstLine"); oTableSecondLine = document.getElementById("tableSecondLine");
// set styles oTable.className = "Table1"; oTableHead.className = "TableHead1"; oTableFirstLine.className = "TableContent1"; oTableSecondLine.className = "TableContent1";
}

// Change table style to style 2 function setStyle2()
{
// obtain references to HTML elements oTable = document.getElementById("table");
oTableHead = document.getElementById("tableHead"); oTableFirstLine = document.getElementById("tableFirstLine"); oTableSecondLine = document.getElementById("tableSecondLine");
// set styles oTable.className = "Table2"; oTableHead.className = "TableHead2"; oTableFirstLine.className = "TableContent2"; oTableSecondLine.className = "TableContent2";
}

4. Finally create the CSS file, styles.css:
.Table1
{
border: DarkGreen 1px solid;
background-color: LightGreen;
}
.TableHead1
{
font-family: Verdana, Arial;
font-weight: bold;

font-size: 10pt;
}
.TableContent1
{
font-family: Verdana, Arial;
font-size: 10pt;
}

.Table2
{
border: DarkBlue 1px solid;
background-color: LightBlue;
}
.TableHead2
{
font-family: Verdana, Arial;
font-weight: bold;
font-size: 10pt;
}
.TableContent2
{
font-family: Verdana, Arial;
font-size: 10pt;
}

5. Load http://localhost/ajax/foundations/css/css.html in your web browser, and test that your buttons work as they should.

Figure 2.5: Table with CSS and JavaScript

What Just Happened?
Your styles.css file contains two sets of styles that can be applied to the table in csstest.html. When the user clicks one of the Set Style buttons, the JavaScript DOM is used to assign those styles to the elements of the table.

In the first part of the SetStyle methods, we use the getElementByID function to obtain references to the HTML elements that we want to apply CSS styles to:

// obtain references to HTML elements oTable = document.getElementById("table"); oTableHead = document.getElementById("tableHead");
oTableFirstLine = document.getElementById("tableFirstLine");
oTableSecondLine = document.getElementById("tableSecondLine");

As with many other web development tasks, manipulating CSS can be the subject of significant inconsistencies between different browsers. For example, in the previous code snippet, try to rename the object names to be the same as their associated HTML
elements (such as renaming oTable to table) to see Internet Explorer stop working. Internet Explorer doesn't like it if there's already an object with that ID in the HTML file. This problem doesn't make much sense because the objects have different scopes, but better watch out if you want your code to work with Internet Explorer as well.

Once initializing these objects, the safe way that works with all browsers to set the elements' CSS
style is to use their className property:

// set styles oTable.className = "Table1"; oTableHead.className = "TableHead1"; oTableFirstLine.className = "TableContent1"; oTableSecondLine.className = "TableContent1";

Using the XMLHttpRequest Object
XMLHttpRequest is the object that enables the JavaScript code to make asynchronous HTTP server requests. This functionality allows you to make HTTP requests, receive responses, and update
parts of the page completely in the background, without the user experiencing any visual interruptions. This is very important because one can keep the user interface responsive while interrogating the server for data.

The XMLHttpRequest object was initially implemented by Microsoft in 1999 as an ActiveX object in Internet Explorer, and eventually became de facto standard for all the browsers, being supported as a native object by all modern web browsers except Internet Explorer 6.

Note that even if XMLHttpRequest has become a de facto standard in the web browsers, it is not a W3C standard. Similar functionality is proposed by the W3C DOM Level 3 Load and Save specification standard, which hasn't been implemented yet by web browsers.

The typical sequence of operations when working with XMLHttpRequest is as follows:

1. Create an instance of the XMLHttpRequest object.
2. Use the XMLHttpRequest object to make an asynchronous call to a server page, defining a callback function that will be executed automatically when the server response is received.
1. Deal with server's response in the callback function.
2. Go to step 2.
Let's now see how to do these steps with real code.

Creating the XMLHttpRequest Object
The XMLHttpRequest is implemented in different ways by the browsers. In Internet Explorer 6 and older, XMLHttpRequest is implemented as an ActiveX control, and you instantiate it like this:

xmlhttp = new ActiveXObject("Microsoft.XMLHttp");

For the other web browsers, XMLHttpRequest is a native object, so you create instances of it like this:

xmlhttp = new XMLHttpRequest();

The ActiveX XMLHttp library comes is many more flavors and versions that you could imagine. Each piece of Microsoft software, including Internet Explorer and MDAC, came with new versions of this ActiveX control. Microsoft.XMLHTTP is the oldest and can be safely used for basic operations, while the newer versions have performance and feature improvements. You will learn how to automatically use a more recent version.

A simplified version of the code we will use for cross-browser XMLHttpRequest instantiation throughout this book is:

// creates an XMLHttpRequest instance function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object var xmlHttp;
// this should work for all browsers except IE6 and older
try
{
// try to create XMLHttpRequest object
xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
}
catch(e) { }
}
// return the created object or display an error message
if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}

This function is supposed to return an instance of the XMLHttpRequest object. The functionality relies on the JavaScript try/catch construct.

The try/catch construct, initially implemented with OOP languages, offers a powerful exception-handling technique in JavaScript. Basically, when an error happens in JavaScript code, an exception is thrown. The exception has the form of an object that contains the error's (exception's) details. Using the try/catch syntax, you can catch the exception and handle it locally, so that the error won't be propagated to the user's browser.

The try/catch syntax is as follows:

try
{
// code that might generate an exception
}
catch (e)
{
// code that is executed only if an exception was thrown by the try block
// (exception details are available through the e parameter)
}

You place any code that might generate errors inside the try block. If an error happens, the execution is passed immediately to the catch block. If no error happens inside the try block, then the code in the catch block never executes.

Run-time exceptions propagate from the point they were raised, up through the call stack of your program. If you don't handle the exception locally, it will end up getting caught by the web browser, which may display a not very good looking error message to your visitor.

The way you respond to each exception depends very much on the situation at hand. Sometimes you will simply ignore the error, other times you will flag it somehow in the code, or you will display an error message to your visitor. Rest assured that in this book you will meet all kinds of scenarios.

In our particular case, when we want to create an XMLHttpRequest object, we will first try to create the object as if it was a native browser object, like this:

// this should work for all browsers except IE6 and older try
{
// try to create XMLHttpRequest object xmlHttp = new XMLHttpRequest();
}

Internet Explorer 7, Mozilla, Opera, and other browsers will execute this piece of code just fine,
and no error will be generated, because XMLHttpRequest is a natively supported. However, Internet Explorer 6 and its older versions won't recognize the XMLHttpRequest object, an exception will be generated, and the execution will be passed to the catch block. For Internet Explorer 6 and older
versions, the XMLHttpRequest object needs to be created as an ActiveX control:

catch(e)
{
// assume IE6 or older try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
}
catch(e) { }
}

The larger the number of JavaScript programmers, the more XMLHttpRequest object creation methods you will see, and surprisingly enough, they will all work fine. In this book, we prefer the method that uses try and catch to instantiate the object, because we think it has the best chance of working well with future browsers, while doing a proper error checking without consuming too many lines of code.

You could, for example, check whether your browser supports XMLHttpRequest before trying to instantiate it, using the typeof function:

if (typeof XMLHttpRequest != "undefined")
xmlHttp = new XMLHttpRequest();

Using typeof can often prove to be very helpful. In our particular case, using typeof doesn't eliminate the need to guard against errors using try/catch, so you would just end up typing more lines of code.

An alternative way to achieve the same functionality is by using a JavaScript feature called object detection. This feature allows you to check whether a particular object is supported by the browser, and works like this:

if (window.XMLHttpRequest)
xmlHttp = new XMLHttpRequest();

For example, by checking for window.ActiveX you can find if the browser is Internet Explorer. Once again, we're not using this technique because it would simply add more lines of code without bringing any benefits; but the ideas are good to keep nevertheless.

If you decide to use object detection, please be sure to check for XMLHttpRequest first before checking for ActiveX support. The reason for this recommendation is Internet Explorer 7, which supports both ActiveX and XMLHttpRequest; the latter is better because it gives you the latest object version. With ActiveX, as you will see, you need to write quite a bit of code to ensure that you get a recent version, although you still are not guaranteed to get the latest one.

At the end of our createXmlHttpRequestObject function, we test that after all the efforts, we have ended up obtaining a valid XMLHttpRequest instance:

// return the created object or display an error message if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;

The reverse effect of object detection is even nicer than the feature itself. Object
detection says that JavaScript will evaluate a valid object instance, such as (xmlHttp), to
true. The nice thing is that (!xmlHttp) expression returns true not only if xmlHttp is
false, but also if it is null or undefined.

Creating Better Objects for Internet Explorer
The one thing that can be improved about the createXmlHttpRequestObject function is to have it recognize the latest version of the ActiveX control, in case the browser is Internet Explorer 6. In most cases, you can rely on the basic functionality provided by ActiveXObject("Microsoft.XMLHttp"), but if you want to try using a more recent version, you can.

The typical solution is to try creating the latest known version, and if it fails, ignore the error and retry with an older version, and so on until you get an object instead of an exception. The latest prog ID of the XMLHTTP ActiveX Object is MSXML2.XMLHTTP.6.0. For more details about these prog IDs, or to simply get a better idea of the chaos that lies behind them, feel free to read a resource such as http://puna.net.nz/etc/xml/msxml.htm.

Here is the upgraded version of createXmlHttpRequestObject. The new bits are highlighted.

// creates an XMLHttpRequest instance function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object
var xmlHttp;
// this should work for all browsers except IE6 and older try
{
// try to create XMLHttpRequest object xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older
var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0',
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP');
// try every prog id until one works
for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++)
{
try
{
// try to create XMLHttpRequest object
xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
}
catch (e) {} // ignore potential error
}
}
// return the created object or display an error message if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}

If this code looks a bit scary, rest assured that the functionality is quite simple. First, it tries to create the MSXML2.XMLHttp.6.0 ActiveX object. If this fails, the error is ignored (note the empty catch block there), and the code continues by trying to create an MSXML2.XMLHTTP.5.0 object, and so on. This continues until one of the object creation attempts succeeds.

Perhaps, the most interesting thing to note in the new code is the way we use object detection (!xmlHttp) to ensure that we stop looking for new prog IDs after the object has been created, effectively interrupting the execution of the for loop.

Initiating Server Requests Using XMLHttpRequest
After creating the XMLHttpRequest object you can do lots of interesting things with it. Although, it has different ways of being instantiated, depending on the version and browser, all the instances of XMLHttpRequest are supposed to share the same API (Application Programming Interface) and support the same functionality. (In practice, this can't be guaranteed, since every browser has its own separate implementation.)

You will learn the most interesting details about XMLHttpRequest by practice, but for a quick reference here are the object's methods and properties:

Method/Property Description

abort() Stops the current request.

getAllResponseHeaders() Returns the response headers as a string.

getResponseHeader("headerLabel") Returns a single response header as a string.

open("method", "URL"[, asyncFlag[, "userName"[, "password"]]])

Initializes the request parameters.

send(content) Performs the HTTP request. setRequestHeader("label", "value") Sets a label/value pair to the request header. onreadystatechange Used to set the callback function that handles request
state changes.

readyState Returns the status of the request:
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete

responseText Returns the server response as a string. responseXML Returns the server response as an XML document. Status Returns the status code of the request.
statusText Returns the status message of the request.

The methods you will use with every server request are open and send. The open method configures a request by setting various parameters, and send makes the request (accesses the server). When the request is made asynchronously, before calling send you will also need to set the onreadystatechange property with the callback method to be executed when the status of the request changes, thus enabling the AJAX mechanism.

The open method is used for initializing a request. It has two required parameters and a few optional ones. The open method doesn't initiate a connection to the server; it is only used to set the connection options. The first parameter specifies the method used to send data to the server page, and it can have a value of GET, POST, or PUT. The second parameter is URL, which specifies where you want to send the request. The URL can be complete or relative. If the URL doesn't specify a resource accessible via HTTP, the first parameter is ignored.

The third parameter of open, called async, specifies whether the request should be handled asynchronously; true means that script processing carries on after the send() method returns without waiting for a response; false means that the script waits for a response before continuing processing, freezing the web page functionality. To enable asynchronous processing, you will seed to set async to true, and handle the onreadystatechange event to process the response from the server.

When using GET to pass parameters, you send the parameters using the URL's query string, as in http://localhost/ajax/test.php?param1=x&param2=y. This server request passes two parameters—a parameter called param1 with the value x, and a parameter called param2 with the value y.

// call the server page to execute the server side operation xmlHttp.open("GET", "http://localhost/ajax/test.php?param1=x&param2=y", true); xmlHttp.onreadystatechange = handleRequestStateChange;
xmlHttp.send(null);

When using POST, you send the query string as a parameter of the send method, instead of joining it on to the base URL, like this:

// call the server page to execute the server side operation xmlHttp.open("POST", "http://localhost/ajax/test.php", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send("param1=x&param2=y");

The two code samples should have the same effects. In practice, using GET can help with debugging because you can simulate GET requests with a web browser, so you can easily see with your own eyes what your server script generates. The POST method is required when sending data larger than 512 bytes, which cannot be handled by GET.

In our examples, we will place the code that makes the HTTP request inside a function called process() in the JavaScript file. The minimal implementation, which is quite fragile and doesn't implement any error-handling techniques, looks like this:

function process()
{
// call the server page to execute the server side operation xmlHttp.open("GET", "server_script.php", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null);
}

This method has the following potential problems:

• process() may be executed even if xmlHttp doesn't contain a valid XMLHttpRequest instance. This may happen if, for example, the user's browser doesn't support XMLHttpRequest. This would cause an unhandled exception to happen, so our other efforts to handle errors don't help very much if we aren't consistent and do something about the process function as well.
• process() isn't protected against other kinds of errors that could happen. For example, as you will see later in this chapter, some browsers will generate a security exception if they don't like the server you want to access with the XMLHttpRequest object (more on security in Chapter 3).

The safer version of process() looks like that:

// called to read a file from the server function process()
{
// only continue if xmlHttp isn't void
if (xmlHttp)
{
// try to connect to the server
try
{
// initiate reading the a file from the server
xmlHttp.open("GET", "server_script.php", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null);
}
// display the error in case of failure catch (e)
{
alert("Can't connect to server:\n" + e.toString());
}
}
}

If xmlHttp is null (or false) we don't display yet another message, as we assume a message was already displayed by the createXmlHttpRequestObject function. We make sure to display any other connection problems though.

Handling Server Response
When making an asynchronous request (such as in the code snippets presented earlier), the execution of xmlHttp.send() doesn't freeze until the server response is received; instead, the execution continues normally. The handleRequestStateChange method is the callback method that we set to handle request state changes. Usually this is called four times, for each time the request enters a new stage. Remember the readyState property can be any of the following:

0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete

Except state 3, all the others are pretty self-explaining names. The interactive state is an intermediate state when the response has been partially received. In our AJAX applications we will only use the complete state, which marks that a response has been received from the server.

The typical implementation of handleRequestStateChange is shown in the following code snippet, which highlights the portion where you actually get to read the response from the server:

// function executed when the state of the request changes function handleRequestStateChange()
{
// continue if the process is completed if (xmlHttp.readyState == 4)
{
// continue only if HTTP status is "OK" if (xmlHttp.status == 200)
{
// retrieve the response
response = xmlHttp.responseText;

// (use xmlHttp.responseXML to read an XML response as a DOM object)
// do something with the response
// ...
// ...
}
}
}

Once again we can successfully use try/catch to handle errors that could happen while initiating a connection to the server, or while reading the response from the server.

A safer version of the handleRequestStateChange method looks like this:

// function executed when the state of the request changes function handleRequestStateChange()
{
// continue if the process is completed if (xmlHttp.readyState == 4)
{
// continue only if HTTP status is "OK" if (xmlHttp.status == 200)
{
try
{
// retrieve the response
response = xmlHttp.responseText;
// do something with the response
// ...
// ...
}
catch(e)
{
// display error message
alert("Error reading the response: " + e.toString());
}
}
else
{
// display status message
alert("There was a problem retrieving the data:\n" +
xmlHttp.statusText);
}
}
}

OK, let's see how these functions work in action.

Time for Action—Making Asynchronous Calls with XMLHttpRequest
1. In the foundations folder, create a subfolder named async.
2. In the async folder, create a file called async.txt, and add the following text to it:
Hello client!

3. In the same folder create a file called async.html, and add the following code to it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: Using XMLHttpRequest</title>
<script type="text/javascript" src="async.js"></script>
</head>
<body onload="process()"> Hello, server!

<br/>
<div id="myDivElement" />
</body>
</html>

4. Create a file called async.js with the following contents:
// holds an instance of XMLHttpRequest
var xmlHttp = createXmlHttpRequestObject();

// creates an XMLHttpRequest instance function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object var xmlHttp;
// this should work for all browsers except IE6 and older
try
{
// try to create XMLHttpRequest object
xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older
var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0",
"MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP");
// try every prog id until one works
for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++)
{
try
{
// try to create XMLHttpRequest object
xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
}
catch (e) {}
}
}
// return the created object or display an error message if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}

// called to read a file from the server function process()
{
// only continue if xmlHttp isn't void if (xmlHttp)
{
// try to connect to the server try
{
// initiate reading the async.txt file from the server xmlHttp.open("GET", "async.txt", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null);
}
// display the error in case of failure
catch (e)

{
alert("Can't connect to server:\n" + e.toString());
}
}
}

// function that handles the HTTP response function handleRequestStateChange()
{
// obtain a reference to the <div> element on the page myDiv = document.getElementById("myDivElement");
// display the status of the request if (xmlHttp.readyState == 1)
{
myDiv.innerHTML += "Request status: 1 (loading) <br/>";
}
else if (xmlHttp.readyState == 2)
{
myDiv.innerHTML += "Request status: 2 (loaded) <br/>";
}
else if (xmlHttp.readyState == 3)
{
myDiv.innerHTML += "Request status: 3 (interactive) <br/>";
}
// when readyState is 4, we also read the server response else if (xmlHttp.readyState == 4)
{
// continue only if HTTP status is "OK" if (xmlHttp.status == 200)
{
try
{
// read the message from the server response = xmlHttp.responseText;
// display the message
myDiv.innerHTML +=
"Request status: 4 (complete). Server said: <br/>";
myDiv.innerHTML += response;
}
catch(e)
{
// display error message
alert("Error reading the response: " + e.toString());
}
}
else
{
// display status message
alert("There was a problem retrieving the data:\n" +
xmlHttp.statusText);
}
}
}

5. Load the async.html file through the HTTP server by loading http://localhost/ ajax/foundations/async/async.html in your browser (you must load it through HTTP; local access won't work this time). Expect to see the results similar to those shown in Figure 2.6:

Figure 2.6: The Four HTTP Request Status Codes

Don't worry if your browser doesn't display exactly the same message. Some XMLHttpRequest implementations simply ignore some status codes. Opera, for example, will only fire the event for status codes 3 and 4. Internet Explorer will report status codes
2, 3, and 4 when using a more recent XMLHttp version.

What Just Happened?
To understand the exact flow of execution, let's start from where the processing begins—the
async.html file:

<html>
<head>
<title>AJAX Foundations: Using XMLHttpRequest</title>
<script type="text/javascript" src="async.js"></script>
</head>
<body onload="process()">

This bit of code hides some interesting functionality. First, it references the async.js file, the moment at which the code in that file is parsed. Note that the code residing in JavaScript functions does not execute automatically, but the rest of the code does. All the code in our JavaScript file is packaged as functions, except one line:

// holds an instance of XMLHttpRequest
var xmlHttp = createXmlHttpRequestObject();

This way we ensure that the xmlHttp variable contains an XMLHttpRequest instance right from the start. The XMLHttpRequest instance is created by calling the createXmlHttpRequestObject function that you encountered a bit earlier.

The process() method gets executed when the onload event fires. The process() method can rely on the xmlHttp object being already initialized, so it only focuses on initializing a server request. The proper error-handling sequence is used to guard against potential problems. The code that initiates the server request is:

// initiate reading the async.txt file from the server xmlHttp.open("GET", "async.txt", true);

xmlHttp.onreadystatechange = handleRequestStateChange;
xmlHttp.send(null);

Note that you cannot load the script locally, directly from the disk using a file:// resource. Instead, you need to load it through HTTP. To load it locally, you would need to mention the complete access path to the .txt file, and in that case you may meet a security problem that we will deal with later.

Supposing that the HTTP request was successfully initialized and executed asynchronously, the handleRequestStateChange method will get called every time the state of the request changes. In real applications we will ignore all states except 4 (which signals the request has completed), but in this exercise we print a message with each state so you can see the callback method actually gets executed as advertised.

The code in handleRequestStateChange is not that exciting by itself, but the fact that it's being called for you is very nice indeed. Instead of waiting for the server to reply with a synchronous HTTP call, making the request asynchronously allows you to continue doing other tasks until a response is received.

The handleRequestStateChange function starts by obtaining a reference to the HTML element called myDivElement, which is used to display the various states the HTTP request is going through:

// function that handles the HTTP response function handleRequestStateChange()
{
// obtain a reference to the <div> element on the page myDiv = document.getElementById("myDivElement");
// display the status o the request if (xmlHttp.readyState == 1)
{
myDiv.innerHTML += "Request status: 1 (loading) <br/>";
}
else if (xmlHttp.readyState == 2)
...
...

When the status hits the value of 4, we have the typical code that deals with reading the server response, hidden inside xmlHttp.ResponseText:

// when readyState is 4, we also read the server response else if (xmlHttp.readyState == 4)
{
// continue only if HTTP status is "OK" if (xmlHttp.status == 200)
{
try
{
// read the message from the server
response = xmlHttp.responseText;
// display the message
myDiv.innerHTML += "Request status: 4 (complete). Server said: <br/>";
myDiv.innerHTML += response;
}
catch(e)
{
// display error message
alert("Error reading the response: " + e.toString());
}

}
else
{
// display status message
alert("There was a problem retrieving the data:\n" +
xmlHttp.statusText);
}
}

Apart from the error-handling bits, it's good to notice the xmlHttp.responseText method that reads the response from the server. This method has a bigger brother called xmlHttp.responseXml, which can be used when the response from the server is in XML format.

Unless the responseXml method of the XMLHttpRequest object is used, there's really no XML appearing anywhere, except for the name of that object (the exercise you have just completed is a perfect example of this). A better name for the object would have been "HttpRequest". The XML prefix was probably added by Microsoft because it sounded good at that moment, when XML was a big buzzword as AJAX is nowadays. Don't be surprised if you will see objects called AjaxRequest (or similar) in the days to come.

Working with XML Structures
XML documents are similar to HTML documents in that they are text-based, and contain hierarchies of elements. In the last few years, XML has become very popular for packaging and delivering all kinds of data.

Incidentally, XML puts the X in AJAX, and the prefix in XMLHttpRequest. However, once again, note that using XML is optional. In the previous exercise, you created a simple application that made an asynchronous call to the server, just to receive a text document; no XML was involved.

XML is a vast subject, with many complementary technologies. You will hear people talking about DTDs, schemas and namespaces, XSLT and XPath, XLink and XPointer, and more. In this book we will mostly use XML for transmitting simple structures of data. For a quick-start introduction to XML we recommend http://www.xmlnews.org/ docs/xml-basics.html. If you don't mind the ads, http://www.w3schools.com/ xml/default.asp is a good resource as well. Appendix C available at http://ajaxphp.packtpub.com contains an introduction to XSLT and Xpath.

You can use the DOM to manipulate XML files just as you did for manipulating HTML files. The following exercise is similar to the previous exercise in that you read a static file from the server. The novelty is that the file is XML, and we read it using the DOM.

Time for Action—Making Asynchronous Calls with XMLHttpRequest and XML
1. In the foundations folder create a subfolder called xml.
2. In the xml folder, create a file called books.xml, which will contain the XML structure that we will read using JavaScript's DOM. Add the following content to the file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<response>
<books>
<book>
<title>
Building Reponsive Web Applications with AJAX and PHP
</title>
<isbn>
1-904811-82-5
</isbn>
</book>
<book>
<title>
Beginning PHP 5 and MySQL E-Commerce: From Novice to Professional
</title>
<isbn>
1-59059-392-8
</isbn>
</book>
</books>
</response>

3. In the same folder create a file called books.html, and add the following code to it:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<title>AJAX Foundations: JavaScript and XML</title>
<script type="text/javascript" src="books.js"></script>
</head>
<body onload="process()">
Server, tell me your favorite books!
<br/>
<div id="myDivElement" />
</body>
</html>

4. Finally, create the books.js file:
// holds an instance of XMLHttpRequest
var xmlHttp = createXmlHttpRequestObject();

// creates an XMLHttpRequest instance function createXmlHttpRequestObject()
{
// will store the reference to the XMLHttpRequest object var xmlHttp;
// this should work for all browsers except IE6 and older try
{
// try to create XMLHttpRequest object xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// assume IE6 or older
var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0',
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP');
// try every prog id until one works
for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++)
{
try

{
// try to create XMLHttpRequest object
xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
}
catch (e) {}
}
}
// return the created object or display an error message
if (!xmlHttp)
alert("Error creating the XMLHttpRequest object.");
else
return xmlHttp;
}

// read a file from the server function process()
{
// only continue if xmlHttp isn't void if (xmlHttp)
{
// try to connect to the server try
{
// initiate reading a file from the server xmlHttp.open("GET", "books.xml", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null);
}
// display the error in case of failure
catch (e)
{
alert("Can't connect to server:\n" + e.toString());
}
}
}

// function called when the state of the HTTP request changes function handleRequestStateChange()
{
// when readyState is 4, we are ready to read the server response if (xmlHttp.readyState == 4)
{
// continue only if HTTP status is "OK" if (xmlHttp.status == 200)
{
try
{
// do something with the response from the server handleServerResponse();
}
catch(e)
{
// display error message
alert("Error reading the response: " + e.toString());
}
}
else
{
// display status message
alert("There was a problem retrieving the data:\n" +
xmlHttp.statusText);
}
}
}

// handles the response received from the server function handleServerResponse()
{
// read the message from the server
var xmlResponse = xmlHttp.responseXML;
// obtain the XML's document element xmlRoot = xmlResponse.documentElement;
// obtain arrays with book titles and ISBNs
titleArray = xmlRoot.getElementsByTagName("title");
isbnArray = xmlRoot.getElementsByTagName("isbn");
// generate HTML output
var html = "";
// iterate through the arrays and create an HTML structure for (var i=0; i<titleArray.length; i++)
html += titleArray.item(i).firstChild.data +
", " + isbnArray.item(i).firstChild.data + "<br/>";
// obtain a reference to the <div> element on the page
myDiv = document.getElementById("myDivElement");
// display the HTML output
myDiv.innerHTML = "Server says: <br />" + html;
}

5. Load http://localhost/ajax/foundations/xml/books.html:

Figure 2.7: The Server Knows What It's Talking About

What Just Happened?
Most of the code will already start looking familiar, as it builds the basic framework we have built so far. The novelty consists in the handleServerResponse function, which is called from handleRequestStateChange when the request is complete.

The handleServerResponse function starts by retrieving the server response in XML format:

// handles the response received from the server function handleServerResponse()
{
// read the message from the server
var xmlResponse = xmlHttp.responseXML;

The responseXML method of the XMLHttpRequest object wraps the received response as a DOM document. If the response isn't a valid XML document, the browser might throw an error. However this depends on the specific browser you're using, because each JavaScript and DOM implementation behaves in its own way.

We will get back to bulletproofing the XML reading code in a minute; for now, let us assume the XML document is valid, and let's see how we read it. As you know, an XML document must have one (and only one) document element, which is the root element. In our case this is <response>. You will usually need a reference to the document element to start with, as we did in our exercise:

// obtain the XML's document element xmlRoot = xmlResponse.documentElement;

The next step was to create two arrays, one with book titles and one with book ISBNs. We did that using the getElementsByTagName DOM function, which parses the entire XML file and retrieves the elements with the specified name:

// obtain arrays with book titles and ISBNs titleArray = xmlRoot.getElementsByTagName("title"); isbnArray = xmlRoot.getElementsByTagName("isbn");

This is, of course, one of the many ways in which you can read an XML file using the DOM. A much more powerful way is to use XPath, which allows you to define powerful queries on your XML document. .

The two arrays that we generated are arrays of DOM elements. In our case, the text that we want displayed is the first child element of the title and isbn elements (the first child element is the text element that contains the data we want to display).

// generate HTML output var html = "";
// iterate through the arrays and create an HTML structure for (var i=0; i<titleArray.length; i++)
html += titleArray.item(i).firstChild.data +
", " + isbnArray.item(i).firstChild.data + "<br/>";
// obtain a reference to the <div> element on the page myDiv = document.getElementById('myDivElement');
// display the HTML output
myDiv.innerHTML = "Server says: <br />" + html;
}

The highlighted bits are used to build an HTML structure that is inserted into the page using the
div element that is defined in books.html.

Handling More Errors and Throwing Exceptions
As highlighted earlier, if the XML document you're trying to read is not valid, each browser reacts in its own way. We have made a simple test by removing the closing </response> tag from books.xml. Firefox will throw an error to the JavaScript console, but besides that, no error will be shown to the user. This is not good, of course, because not many users browse websites looking at the JavaScript console.

Open the Firefox JavaScript console from Tools | JavaScript Console. Please see Appendix B at http://ajaxphp.packtpub.com for more details about the JavaScript Console and other excellent tools that help with debugging.

Figure 2.8: The Firefox JavaScript Console is Very Useful

What's really nasty is that all tested browsers except Internet Explorer (all versions) don't catch the error using the try/catch mechanism that exists in place for exactly this kind of errors. Just like Firefox, Mozilla 1.7 doesn't throw any errors, and to make things even worse, it doesn't say anything even in its JavaScript console. It simply ignores everything and behaves like nothing bad happened, as shown in Figure 2.9 (the output is similar to Firefox's).

Figure 2.9: Mozilla Keeps the Problem Secret

Opera, on the other hand, is friendlier (if you're the developer, at least). While it completely
ignores the try/catch blocks that were supposed to catch the error, it displays a very detailed error message. While this is good for development, for certain you don't want your visitors to see anything like that:

Figure 2.10: Opera Displays the Most Helpful Error Message

For some reason, at the time of writing, Internet Explorer seems to be the only browser where our
catch block intercepts the exception, and displays an error message (not a very helpful one, though):

Figure 2.11: Exception Caught by Internet Explorer

Either by design or by default, web browsers don't do very a good job at trapping your errors as we would expect them to. Since certain kinds of errors are not trappable by normal try/catch mechanisms, it is important to find alternative solutions (because, the good news is, there are solutions). You can fix your XML reading code by updating the handleServerResponse function like this:

// handles the response received from the server function handleServerResponse()
{
// read the message from the server
var xmlResponse = xmlHttp.responseXML;
// catching potential errors with IE and Opera
if (!xmlResponse || !xmlResponse.documentElement)
throw("Invalid XML structure:\n" + xmlHttp.responseText);
// catching potential errors with Firefox
var rootNodeName = xmlResponse.documentElement.nodeName;
if (rootNodeName == "parsererror")
throw("Invalid XML structure:\n" + xmlHttp.responseText);
// obtain the XML's document element

xmlRoot = xmlResponse.documentElement;
// obtain arrays with book titles and ISBNs
titleArray = xmlRoot.getElementsByTagName("title");
isbnArray = xmlRoot.getElementsByTagName("isbn");
// generate HTML output
var html = "";
// iterate through the arrays and create an HTML structure for (var i=0; i<titleArray.length; i++)
html += titleArray.item(i).firstChild.data +
", " + isbnArray.item(i).firstChild.data + "<br/>";
// obtain a reference to the <div> element on the page
myDiv = document.getElementById("myDivElement");
// display the HTML output
myDiv.innerHTML = "Server says: <br />" + html;
}

With Internet Explorer and Opera, the documentElement property of xmlResponse object will be null if the underlying XML document is not valid. With Firefox, the XML document will be perfectly valid, but the document itself will be replaced by one containing the error details (yes, an interesting way to report errors); in such cases the document element will be called parsererror.

When we find out there's something wrong with the received XML document, we throw an exception. Throwing an exception means generating a custom-made exception, and is done using the throw keyword in JavaScript. This exception will be caught by the catch block in handleServerResponse, and will get displayed to the visitor:

Figure 2.12: Error Message that Gets Displayed by All Tested Browsers

I admit that the following piece of code may have puzzled you:

if (!xmlResponse || !xmlResponse.documentElement)
throw("Invalid XML structure:\n" + xmlHttp.responseText);

Apparently, if xmlResponse is void, we risk generating another error when trying to read its documentElement property. In practice, the JavaScript interpreter only evaluates logical expressions when necessary, and it does so from left to right. In our particular case, if (!xmlResponse) is true, the second expression isn't evaluated at all, because the end result is true anyway. This feature, which is implemented in JavaScript and other languages, is called short-circuit evaluation and
you can read more about it here: http://www.webreference.com/javascript/reference/
core/expr.html.

Creating XML Structures
XML and DOM are everywhere. In this chapter, you used the DOM to create HTML elements on the existing DOM object called document, and you also learned how to read XML documents received from the server. An important detail that we didn't cover was creating brand new XML documents using JavaScript's DOM. You may need to perform this kind of functionality if you want to create XML documents on the client, and send them for reading on the server.

We won't go through more examples, but we will only show you the missing bits. The trick with creating a brand new XML document is creating the XML document itself. When adding elements to the HTML output, you used the implicit document object, but this is not an option when you need to create a new document.

When creating a new DOM object with JavaScript, we're facing the same problem as with creating XMLHttpRequest objects; the method of creating the object depends on the browser. The following function is a universal function that returns a new instance of a DOM object:

function createDomObject()
{
// will store reference to the DOM object
var xmlDoc;
// create XML document
if (document.implementation && document.implementation.createDocument)
{
xmlDoc = document.implementation.createDocument("", "", null);
}
// works for Internet Explorer else if (window.ActiveXObject)
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
}
// returns the created object or displays an error message
if (!xmlDoc)
alert("Error creating the DOM object.");
else
return xmlDoc;

}

After executing this function, you can use the created DOM object to perform whatever actions you want. For more details about creating the DOM object check the following link: http://www.webreference.com/programming/javascript/domwrapper/index.html. For details of using the DOM object, refer to the DOM articles mentioned earlier in this chapter.

Summary
This chapter walked you through many fields. Working with HTML, JavaScript, CSS, the DOM, XML, and XMLHttpRequest is certainly not easy to start with, especially if some of these technologies are new to you. Where you don't feel confident enough, have a look at the aforementioned resources. When you feel ready, proceed to Chapter 3, where you will learn how to use PHP and MySQL on the server, and make them interact nicely with the AJAX-enabled client.

0 comments: