Chapter 18. A Touch of AJAX

After reading this chapter, you'll be able to

  • Understand the basics of the Asynchronous JavaScript and XML (AJAX) programming paradigm.

  • Understand the difference between a synchronous and an asynchronous AJAX call.

  • Use AJAX to retrieve data.

  • Use AJAX with different Hypertext Transfer Protocol (HTTP) methods to retrieve responses from a server.

Introduction to AJAX

Asynchronous JavaScript and XML (AJAX) describes the programming paradigm that combines JavaScript and a Web server. AJAX is used to create highly interactive Web applications such as Microsoft Virtual Earth.

Without AJAX, a Web application might make the visitor wait while a response is gathered from the Web server. An AJAX-based application sends requests from the Web browser to the Web server in the background (asynchronously) while the visitor is using the application. This makes the application feel much more responsive to the user.

In an AJAX application, JavaScript processes the response and presents it to the user. When combined with Cascading Style Sheets (CSS) and a good layout, an AJAX application provides excellent usability while also giving the portability that only a Web application can.

As complex as some AJAX applications may seem, the actual process of sending a request and handling the response are really uncomplicated. This chapter looks at how to send and receive requests using a fundamental AJAX object, XMLHttpRequest.

One of the central themes in AJAX is using a server-side application to return data. I'll show a brief example of how to create such an application using both Active Server Pages (ASP) and PHP (PHP is a recursive acronym for PHP Hypertext Preprocessor) later in the chapter. However, should you need additional assistance in creating the server-side portion of an AJAX application, you can get help from several sources.

If you're creating a server-side application using Microsoft technologies, the Microsoft Developer Network provides a great resource with many tutorials, including http://msdn2.microsoft.com/en-us/library/98wzsc30.aspx. For an AJAX overview, check out MSDN Magazine (http://msdn.microsoft.com/msdnmag/issues/07/09/CuttingEdge/). Microsoft Press also publishes several excellent books on building applications for the Web. One such title is Microsoft ASP.NET 2.0 Step By Step (Microsoft Press 2005), and there are many others. Look at http://www.microsoft.com/mspress for more information.

If you're developing a server-side application using other technologies such as the LAMP (Linux, Apache, MySQL, Perl/PHP/Python) stack, searching the Web for tutorials is likely the easiest way to get up to speed quickly on development on the platform. The book Learning Perl (O'Reilly, 2005) is a great resource to learn the basics of the Perl programming language. PHP's main Web site (http://www.php.net) is a good place to start for information on PHP. The same goes for Python (http://www.python.org).

The XMLHttpRequest Object

The XMLHttpRequest object is central to building an AJAX application. While implementations differ, many aspects of JavaScript have been standardized by the ECMAScript standard and through the World Wide Web Consortium (W3C). However, XMLHttpRequest has never experienced a standardization process. Even so, with the release of Microsoft Windows Internet Explorer 7, usage of XMLHttpRequest is the same across all major browsers.

The XMLHttpRequest object was first implemented in Internet Explorer 5. If a visitor is using a browser version earlier than that, applications using XMLHttpRequest won't work. In Internet Explorer versions prior to version 7, the XMLHttpRequest object was instantiated through the ActiveXObject object. This means that applications that need to work with versions of Internet Explorer earlier than version 7 need to instantiate the XMLHttpRequest object in a different way, as you'll see. The next section, XMLHttpRequest"Instantiating the Object," shows how to test for the existence of XMLHttpRequest and how to instantiate it in Internet Explorer 7 and in Internet Explorer versions earlier than version 7.

Instantiating the XMLHttpRequest Object

Internet Explorer 7 and all major browsers that support XMLHttpRequest instantiate the XMLHttpRequest object in the same way:

var req = new XMLHttpRequest();

Internet Explorer versions earlier than version 7 must use the ActiveXObject. However, the exact way to do this varies depending on the version of the XMLHTTP library installed on the client. Therefore, a bit of code juggling needs to be done in order to instantiate an XMLHttpRequest object in earlier versions of Internet Explorer.

The code in Example 18-1 is a cross-browser function to instantiate the XMLHttpRequest object across multiple browsers.

Example 18-1. Instantiating the XMLHttpRequest Object Across Browsers

function readyAJAX() {
    try {
        return new XMLHttpRequest();
    } catch(e) {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP'),
        } catch(e) {
            try {
                return new ActiveXObject('Microsoft.XMLHTTP'),
            } catch(e) {
                return "A newer browser is needed.";
            }
        }
    }
}

The function in Example 18-1 uses multiple levels of try/catch blocks to instantiate an XMLHttpRequest, whether the visitor is using Internet Explorer or another browser. If the native call to XMLHttpRequest fails, it indicates that the visitor is using an Internet Explorer browser older than version 7. In such a case, the error is caught and one of the ActiveXObject-based methods for instantiating XMLHttpRequest is tried. If none of these methods succeed, the likely reason is that the browser is too old to support XMLHttpRequest.

The article "About Native XMLHTTP" on MSDN describes some of the version history and security nuances of the XMLHttpRequest object in Internet Explorer. This article can be found at http://msdn2.microsoft.com/en-us/library/ms537505.aspx.

The readyAJAX() function shown in Example 18-1 would be called like this:

var requestObj = readyAJAX();

The requestObj variable now contains the XMLHttpRequest object returned by the function, or, if no XMLHttpRequest was able to be returned, the requestObj variable will contain the string "A newer browser is needed."

Sending an AJAX Request

With a newly created XMLHttpRequest object in hand, a request can be sent to the Web server. Sending the request is a combination of using the open() and send() methods of the XMLHttpRequest object.

There are two fundamentally different ways to send AJAX requests: synchronously and asynchronously. When sent in a synchronous manner, the request will block, effectively preventing further processing or execution of other JavaScript while the script awaits the response from the Web server. This process has obvious disadvantages if the request or response gets lost in transit or is just slow.

Before the request can be sent, it must be built. The open method is used to build the request and has three arguments, the request method (GET, POST, HEAD, and others), the Uniform Resource Locator (URL) to which the request will be sent, and true or false, indicating whether the request will be sent asynchronously or synchronously, respectively.

Assuming that a request object has been retrieved using the readyAJAX() function and placed into a variable named requestObj, a typical asynchronous call to the open method might look like this:

var url = "http://www.braingia.org/getdata.php";
requestObj.open("GET", url, true);

That same call sent synchronously looks like this:

var url = "http://www.braingia.org/getdata.php";
requestObj.open("GET", url, false);

Sending the request is done with the send method, as follows:

requestObj.send();

Note

If the parameters sent with the request have any special characters, such as spaces or other characters reserved by the URI RFC, those characters must be escaped using the % notation. This is discussed further within RFC 3986, which can be found at ftp://ftp.rfc-editor.org/in-notes/rfc3986.txt and more information can also be found at http://msdn2.microsoft.com/en-us/library/aa226544(sql.80).aspx.

Processing an AJAX Response

It's easier to work with the response when the request is sent synchronously because the script's execution stops while awaiting the response. This section first looks at synchronous response processing.

The requestObj variable provides helpful methods for processing a response, including giving access to the status codes and text of the status sent from the server. Regardless of whether the request is synchronous or asynchronous, the status code should be evaluated to ensure that the response was successful (usually indicated by a status of 200).

The responseText method contains the text of the response as received from the Web server.

For example, assume that there is a server application that returns the sum of two numbers. Calling the application to add the numbers 2 and 56 looks like this:

http://www.braingia.org/addtwo.php?num1=2&num2=56

Here's a synchronous call and response retrieval:

requestObj.open("GET", "http://www.braingia.org/addtwo.php?num1=2&num2=56", false);
requestObj.send();
if (requestObj.status == 200) {
    alert(requestObj.responseText);
} else {
    alert(requestObj.statusText);
}

In this example, assume that the requestObj is built using the readyAJAX() function. The open method is then called using a GET request to the specified URL (http://www.braingia.org/addtwo.php?num1=2&num2=56) and the request will be sent synchronously because the last argument to the open method is false. The send method is then called, which actually sends the request to the Web server.

The status method is called and if it's a 200 response code, indicating success, then the responseText is displayed. If the response status code was anything other than 200, the text of the response status is displayed.

Processing an asynchronous response is a bit more complex. When a request is sent asynchronously, the script execution continues. Therefore, it is unpredictable when the script will be notified that the response has been received. The onreadystatechange event can trigger code that checks the event's readyState property to ascertain the state of the request/response cycle. Recall from Chapter 17, that the readyState property has five states, as shown in Table 18-1.

Table 18-1. The readyState Property

Value

Description

0

Uninitialized. Open has yet to be called.

1

Open. Initialized but not yet sent.

2

Sent. The request has been sent.

3

Receiving. The response is actively being received.

4

Loaded. The response has been fully received.

For practical purposes, the only state that matters to the JavaScript and AJAX programmer is state 4—Loaded. Attempting to process a response that has a readyState value other than 4 results in an error.

An anonymous function is commonly used for handling the onreadystatechange event with asynchronous JavaScript. The function checks to see if the readyState property has reached 4 and then checks to ensure that the status is 200, indicating success. The code follows this format:

requestObj.onreadystatechange = function() {
    if (requestObj.readyState == 4) {
        if (requestObj.status == 200) {
            alert(requestObj.responseText);
        } else {
            alert(requestObj.statusText);
        }
    }
}

In this next exercise, you'll create an XMLHttpRequest object and send a request to a Web server to retrieve a book title based on its ISBN. For this exercise, you'll need a Web server and Web server code to print the response because requests sent using XMLHttpRequest are subject to the JavaScript Same-Origin policy.

The Same-Origin policy requires that requests go only to servers within the same domain from which the calling script is executing. In other words, because I'm executing the script in this exercise directly from my Web server at http://www.braingia.org, it will be able to retrieve the response. If you run the script from another Web server, however, the Same-Origin policy will prevent the script from retrieving the response.

One way to get around this security feature is to use an HTTP proxy or to write the server-side program so that it sends a request on behalf of the calling program. Doing so is beyond the scope of this book.

For the upcoming exercise, the script or program running on the server needs to return the phrase "JavaScript Step by Step" when a GET request is received with a name/value argument of the following:

isbn=9780735624498

For example, at its most basic, the server-side program could look like this when implemented inside an ASP page:

<%
dim isbn
isbn=Request.QueryString("isbn")
If isbn<>"" Then
    If isbn=="9780735624498" Then      Response.Write("JavaScript Step by Step")
    End If
End If
%>

The program looks like this when implemented through PHP:

<?php

$isbn = $_GET['isbn'];

if (! $isbn) {
    print "That request was not understood.";
} else if ($isbn == "9780735624498") {
    print "JavaScript Step by Step";
}

?>

Within the following exercise, the URL to which the request will be sent is defined. Replace that URL with the URL where you locate the server-side program. Due to the Same-Origin policy, the server-side program needs to be within the same domain as the page that calls it.

Sending and receiving with XMLHttpRequest

  1. Create your server-side program to return the book title when an isbn argument is received. This can be done in your choice of languages (if you need to, look at the two examples shown earlier).

  2. Using Microsoft Visual Studio, Eclipse, or another editor, edit the file isbn.htm in the Chapter 17 sample files folder.

  3. Within the Web page, add the code shown below in bold type, making sure to replace the url variable with the URL where your server-side program is located:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <title>ISBN</title>
    </head>
    <body>
    <div id="data"></div>
    <script type="text/javascript">
    function readyAJAX() {
        try {
            return new XMLHttpRequest();
        } catch(e) {
            try {
                return new ActiveXObject('Msxml2.XMLHTTP'),
            } catch(e) {
                try {
                    return new ActiveXObject('Microsoft.XMLHTTP'),
                } catch(e) {
                    return "A newer browser is needed.";
                }
            }
        }
    }
    var requestObj = readyAJAX();
    var url = "http://www.braingia.org/isbn.php?isbn=9780735624498";
    requestObj.open("GET",url,true);
    requestObj.send();
    requestObj.onreadystatechange = function() {
        if (requestObj.readyState == 4) {
            if (requestObj.status == 200) {
                alert(requestObj.responseText);
            } else {
                alert(requestObj.statusText);
            }
        }
    }
    </script>
    </body>
    </html>
  4. Save and view the page in a Web browser. You should receive an alert like the one shown here.

image with no caption

Congratulations! You've now processed your first XMLHttpRequest.

Processing XML Responses

The AJAX examples shown so far have all used plain Hypertext Markup Language (HTML) and text responses from the Web server. These responses have been retrieved using the responseText method. The server application can also return XML responses, which can be processed natively using the responseXML method.

Earlier in this chapter, in the sidebar titled Describing How the Web Works in 500 Words or Less, an example Web server response was discussed. The server response contained this Content-Type header:

Content-Type: text/html; charset=iso-8859-1

To retrieve a response using the responseXML method, the Web server needs to send a Content-Type of "text/xml" or "application/xml," like this:

Content-Type: application/xml

When native XML is received as the response, Document Object Model (DOM) methods are used to process the response.

The responseXML method has historically been somewhat quirky, meaning that using it can result in unexpected behavior, depending on the browser and operating system. In addition, responseXML isn't as widely supported as other JavaScript methods.

Using responseXML means combining the XMLHttpRequest techniques already seen in this chapter with the XML parsing techniques described in Chapter 17. For example, consider this XML document (let's call it book.xml):

<?xml version="1.0" encoding="ISO-8859-1"?>
<book>
<title>JavaScript Step by Step</title>
<isbn>9780735624498</isbn>
</book>

Combining XMLHttpRequest and XML parsing leads to this code to retrieve and display the ISBN from the book.xml document:

var requestObj = readyAJAX();
var url = "http://www.braingia.org/book.xml";
requestObj.open("GET",url,false);
requestObj.send();
if (requestObj.status == 200) {
    var xmldocument = requestObj.responseXML;
    alert(xmldocument.getElementsByTagName("isbn")[0].childNodes[0].nodeValue);
} else {
    alert(requestObj.statusText);
}

Working with JSON

JavaScript Object Notation (JSON) is a way to pass data as native JavaScript objects and arrays, rather than encoding that data within XML (or HTML) responses. JSON is a more efficient way to pass data from server to client because it bypasses the DOM parsing and enables the data to be used without needing to be converted to JavaScript objects.

Recall the book.xml document from an earlier example in this chapter. That same data in JSON looks like this:

{
"book":
    {
    "title": "JavaScript Step by Step",
    "isbn": "9780735624498"
    }
}

Retrieval of an individual element is somewhat easier with JSON than with XML. The eval() function is used to parse the response with JSON. For example, this code is used to retrieve and display the book title.

var requestObj = readyAJAX();
var url = "http://www.braingia.org/json.php";
requestObj.open("GET",url,false);
requestObj.send();
if (requestObj.status == 200) {
    var xmldocument = eval('(' + requestObj.responseText + ')'),
    alert(xmldocument.book.title);
} else {
    alert(requestObj.statusText);
}

Using JSON carries with it an inherent security risk because it uses the eval() function to parse the response. The eval() function essentially executes the JavaScript code received, so it's possible that, if that code were malicious, it would execute in the context of the application being run. It is the developer's responsibility to ensure that the data being used with JSON is clean and free of malicious code that could cause problems when executed using eval().

Processing Headers

The HTTP HEAD method returns just the response headers from the server, rather than the headers and the body as would be the case with the GET method. The HEAD method is sometimes helpful for determining if a given resource has been updated or changed.

One of the HTTP headers frequently sent is the Expires header, which indicates when the document should be refreshed by the client instead of read from the client's cache. If the Expires header is sent by the server, the HEAD method is an efficient way to view and parse it because it retrieves only the response header rather than the entire body of the requested resource.

The getAllResponseHeaders() method of the XMLHttpRequest object is used to retrieve the response headers, whether using a HEAD request or any other type of request such as GET or POST, as follows:

requestObj.getAllResponseHeaders();

For example, Example 18-2 shows retrieval of response headers from my Web site.

Example 18-2. Retrieving Headers

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Response Headers</title>
</head>
<body>
<div id="data-id001"></div>
<script type="text/javascript">
function readyAJAX() {
    try {
        return new XMLHttpRequest();
    } catch(e) {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP'),
        } catch(e) {
            try {
                return new ActiveXObject('Microsoft.XMLHTTP'),
            } catch(e) {
                return "A newer browser is needed.";
            }
        }
    }
}
var requestObj = readyAJAX();
var url = "http://www.braingia.org/";
requestObj.open("HEAD",url,true);
requestObj.send();
requestObj.onreadystatechange = function() {
    if (requestObj.readyState == 4) {
        if (requestObj.status == 200) {
            alert(requestObj.getAllResponseHeaders());
        } else {
            alert(requestObj.statusText);
        }
    }
}
</script>
</body>
</html>

Note

The Same-Origin policy that you ran into during the exercise earlier in the chapter applies equally to the HEAD method in Example 18-2. When writing Example 18-2, I forgot about the Same-Origin Policy and originally set the url variable to http://www.microsoft.com/. However, upon receiving an error, I realized the problem and changed the url variable to match the domain on which the script was running. Remember to change the url variable when attempting to run the code in Example 18-2.

Using the POST Method

Up to this point, the examples shown have used the GET and HEAD methods to retrieve data from the server. The POST method is also a common way to submit queries through HTTP. Using the POST method with XMLHttpRequest is a bit more complex than either GET or HEAD. However, the POST method offers two specific advantages over the GET method.

First, parameters sent using POST can be sent over a Secure Sockets Layer (SSL) connection. Compare this to a GET request, which sends its parameters directly within the URL, thus possibly making it visible to an eavesdropper. With a POST request, the parameters are contained in the body of the request and therefore are subject to the SSL protocol.

Second, the POST method enables larger requests to be sent. Some servers limit the amount or size of a GET request to a certain number of characters, and while those servers might also limit the size of a POST request, the limitation for POSTs is almost always much greater.

The HTTP POST method requires an additional header to be set within the request. Setting an additional header is accomplished with the setRequestHeader() method.

requestObj.setRequestHeader(header, value);

For example, setting the Content-Type header for a Web form, as would be done for a POST request, looks like this:

requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

Recall that when sending an AJAX request using the GET method, the URL includes the parameters or name/value pairs for the application, like so:

http://www.braingia.org/books/javascriptsbs/isbn.php?isbn=9780735624498

In this example, the isbn parameter is sent using the value 9780735624498. However, when working with POST requests, the URL merely contains the document or resource requested and not any parameters. Therefore, the parameters must be sent as part of the send() method.

Example 18-3 presents an AJAX request using the POST method, shown in bold type. Two parameters are used—see if you can spot them.

Example 18-3. Constructing a POST Request

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Post</title>
</head>
<body>
<div id="xmldata-id002"></div>
<script type="text/javascript">
function readyAJAX() {
    try {
        return new XMLHttpRequest();
    } catch(e) {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP'),
        } catch(e) {
            try {
                return new ActiveXObject('Microsoft.XMLHTTP'),
            } catch(e) {
                return "A newer browser is needed.";
            }
        }
    }
}

var requestObj = readyAJAX();
var url = "http://www.braingia.org/books/javascriptsbs/post.php";
var params = "num1=2&num2=2";
requestObj.open("POST",url,true);
requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
requestObj.send(params);
requestObj.onreadystatechange = function() {
    if (requestObj.readyState == 4) {
        if (requestObj.status == 200) {
            alert(requestObj.responseText);
        } else {
            alert(requestObj.statusText);
        }
    }
}
</script>
</body>
</html>

Within the code in Example 18-3, the parameters are set and placed into a variable called params:

var params = "num1=2&num2=2";

After the request object (requestObj) is constructed, the parameters are sent within the send() method:

requestObj.send(params);

Case Study: Live Searching and Updating

Microsoft partner ICG Media, LLC, a computer services company, offers their customers an AJAX application to aid in management of the customer's e-mail filtering solution. Part of that application is a form to search for e-mail addresses that have been either whitelisted or blacklisted.

The whitelist/blacklist search uses AJAX to import an XML file and provide results based on input from the administrator. This application can easily be adapted to provide live search results or live bookmarks. Chapter 19, will use a portion of that application to create a live search form, and the next section will introduce an adaptation of the application to create a live searchable bookmark feed using XML.

I find it necessary to access Web browser bookmarks from multiple computers. With that in mind, here's an AJAX application that provides a Bookmarks page. The bookmarks are managed in an XML file in a central location. Then a Web page is built to retrieve the bookmarks and give a search interface.

The bookmark application is shown in Figure 18-1. Granted, it's only showing 3 bookmarks, but the application works the same with 3 bookmarks or 300, and providing just a few makes it easier to demonstrate.

A view of the live bookmark application

Figure 18-1. A view of the live bookmark application

The search box works by narrowing down the list of viewed bookmarks as text is typed into the text box. For example, typing the letter m into the text box immediately shows only those bookmarks that begin with the letter m, as depicted in Figure 18-2.

Typing the letter m narrows down the displayed bookmarks to those beginning with m.

Figure 18-2. Typing the letter m narrows down the displayed bookmarks to those beginning with m.

Further typing, for example adding an i to make the characters mi, continues to narrow down the available bookmarks, as shown in Figure 18-3.

Adding additional characters to further narrow down the results

Figure 18-3. Adding additional characters to further narrow down the results

When the text is deleted from the text box, the Bookmarks page goes back to its default (as shown in Figure 18-1).

The XML for this application is shown here:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bookmarks xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <bookmark>
                <title>Steve Suehring's Home Page</title>
                <url>http://www.braingia.org/</url>
        </bookmark>
        <bookmark>
                <title>MSDN</title>
                <url>http://msdn.microsoft.com/</url>
        </bookmark>
        <bookmark>
                <title>Microsoft Press</title>
                <url>http://www.microsoft.com/mspress</url>
        </bookmark>
</bookmarks>

The application itself, along with the Web page, is shown here:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Search</title>
</head>
<body>
<form name="nameform" id="nameform" action="" method="post">
Bookmark Search: <input id="textname" type="text" name="textname">
</form>
<div id="data-id002"></div>
<script type="text/javascript">

function textsearch() {
    var textName = document.getElementById("textname");
    var dataNode = document.getElementById("data");
    while (dataNode.hasChildNodes()) {
        dataNode.removeChild(dataNode.firstChild);
    }
    listName(textName.value);
}

function readyAJAX() {
    try {
        return new XMLHttpRequest();
    } catch(e) {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP'),
        } catch(e) {
            try {
                return new ActiveXObject('Microsoft.XMLHTTP'),
            } catch(e) {
                return "A newer browser is needed.";
            }
        }
    }
}
function listName(text) {
    var xmlEl = AJAXresponse.getElementsByTagName("bookmark");
    for (i = 0; i < xmlEl.length; i++) {
        var div = document.createElement("div");
        // Create the row elements
        for (j = 0; j < xmlEl[i].childNodes.length; j++) {
            // Skip it if the type is not 1
            if (xmlEl[i].childNodes[j].nodeType != 1) {
                continue;
            }
            var url = new RegExp("http");
            if (! xmlEl[i].childNodes[j].firstChild.nodeValue.match(url)) {
                var pattern = "^" + text;
                var title = xmlEl[i].childNodes[j].firstChild.nodeValue;
                var nameRegexp = new RegExp(pattern, "i");
                var existDiv = document.getElementById(title);
                if (! existDiv) {
                    if (title.match(nameRegexp)) {
                        var anchor = document.createElement("a");
                        var xmlData =
                            document.createTextNode(xmlEl[i].childNodes[j].firstChild.
nodeValue);
                        var urls = AJAXresponse.getElementsByTagName("url");
                        anchor.setAttribute("href", urls[i].firstChild.nodeValue);
                        anchor.appendChild(xmlData);
                        div.appendChild(anchor);
                    }
                }
            }
        }
        document.getElementById("data").appendChild(div);
    }
}

var requestObj = readyAJAX();
var url = "http://www.braingia.org/books/javascriptsbs/bookmark.xml";
requestObj.open("GET",url,true);
requestObj.send();
var AJAXresponse;
requestObj.onreadystatechange = function() {
    if (requestObj.readyState == 4) {
        if (requestObj.status == 200) {
            AJAXresponse = requestObj.responseXML;
            listName("");
        } else {
            alert(requestObj.statusText);
        }
    }
}

if (window.attachEvent) {
    document.getElementById("textname").attachEvent("onkeyup",textsearch);
} else {
    document.getElementById("textname").addEventListener("keyup",textsearch,false);
}

</script>
</body>
</html>

The JavaScript portion of the code is broken into several functions, which will be discussed in due course. The HTML for the page consists mainly of only a few lines. Here's the Web form:

<form name="nameform" id="nameform-id001" action="" method="post">
Bookmark Search: <input id="textname-id001" type="text" name="textname">
</form>

And here's the div that will hold each of the bookmarks:

<div id="data-id003"></div>

The JavaScript portion of the code declares several functions and executes the following code within the main block. This code is largely the same as you've seen throughout this chapter already, insofar as it uses the readyAJAX() function and sends an AJAX request for a bookmark XML file to the server. When the response is retrieved, the listName() function is called.

In addition to the AJAX code, an event handler is attached to the Web form's text box. The event to be handled is the onkeyup event, which detects when a key is released within the text box. The code is like this:

var requestObj = readyAJAX();
var url = "http://www.braingia.org/books/javascriptsbs/bookmark.xml";
requestObj.open("GET",url,true);
requestObj.send();
var AJAXresponse;
requestObj.onreadystatechange = function() {
    if (requestObj.readyState == 4) {
        if (requestObj.status == 200) {
            AJAXresponse = requestObj.responseXML;
            listName("");
        } else {
            alert(requestObj.statusText);
        }
    }
}

if (window.attachEvent) {
    document.getElementById("textname").attachEvent("onkeyup",textsearch);
} else {
    document.getElementById("textname").addEventListener("keyup",textsearch,false);
}

The event handler that handles key presses in the search form is contained in two functions, textsearch and listName. The textsearch function is responsible for removing bookmarks from the list, calling the listName() function.

function textsearch() {
    var textName = document.getElementById("textname");
    var dataNode = document.getElementById("data");
    while (dataNode.hasChildNodes()) {
        dataNode.removeChild(dataNode.firstChild);
    }
    listName(textName.value);
}

Finally, the listName() function contains the code to display only those bookmarks that are related to the text that's been typed into the text box. If no text is in the text box, then all bookmarks are shown:

function listName(text) {
    var xmlEl = AJAXresponse.getElementsByTagName("bookmark");
    for (i = 0; i < xmlEl.length; i++) {
        var div = document.createElement("div");
        // Create the row elements
        for (j = 0; j < xmlEl[i].childNodes.length; j++) {
            // Skip it if the type is not 1
            if (xmlEl[i].childNodes[j].nodeType != 1) {
                continue;
            }
            var url = new RegExp("http");
            if (! xmlEl[i].childNodes[j].firstChild.nodeValue.match(url)) {
                var pattern = "^" + text;
                var title = xmlEl[i].childNodes[j].firstChild.nodeValue;
                var nameRegexp = new RegExp(pattern, "i");
                var existDiv = document.getElementById(title);
                if (! existDiv) {
                    if (title.match(nameRegexp)) {
                        var anchor = document.createElement("a");
                        var xmlData =
                            document.createTextNode(xmlEl[i].childNodes[j].firstChild.
nodeValue);
                        var urls = AJAXresponse.getElementsByTagName("url");
                        anchor.setAttribute("href", urls[i].firstChild.nodeValue);
                        anchor.appendChild(xmlData);
                        div.appendChild(anchor);
                    }
               }
           }
       }
       document.getElementById("data").appendChild(div);
   }
}

Exercises

  1. Which of the HTTP request methods covered in this chapter is the most secure? Why?

  2. Describe the differences between an XMLHttpRequest request/response using HTML, XML, and JSON.

  3. Construct a server-side program to return the sum of two numbers that it receives as parameters. Call the program using an asynchronous XMLHttpRequest object.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.195.97