reptile7's JavaScript blog
Friday, May 20, 2011
 
Beginning Ajax for Non-Dummies
Blog Entry #215

Today we will take up HTML Goodies' "How to Develop Web Applications with Ajax: Part 1" tutorial, which is authored by Jonathan Fenocchi and which appeared originally at WebReference.com. The "Ajax" in the tutorial title refers to the Asynchronous JavaScript and XML group of technologies. As this tutorial marks our introduction to Ajax, let me begin by giving you some Ajax-related references:
(1) Mozilla's Ajax portal is as good a place as any to kick off your Ajax education.
(2) Be sure to check out Microsoft's XMLHttpRequest Object page.
(3) The W3C is developing an XMLHttpRequest specification, which is currently at the Candidate Recommendation stage. The W3C's work on an XMLHttpRequest specification has been taken over by the Web Hypertext Application Technology Working Group (WHATWG).
(4) At the end of the tutorial, the author himself links to an Apple Developer "Dynamic HTML and XML: The XMLHttpRequest Object" article.

The Ajax concept - at least as it plays out in the tutorial - is pretty straightforward. We are familiar with the idea of 'linked resources': external files (an image, a style sheet, a script) that a current document might call on. Heretofore the links to these resources were statically set in the current document source; for example, we would link to an external myScript.js JavaScript script via a

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

script element. With Ajax, we will complementarily link to a resource - specifically, an XML document - on the fly and then use that resource's data to modify the current document. Regarding the "A" of Ajax, our request for the XML document will be asynchronous, which in practice means that the request will not cause the operating system to block and that we won't need to wait for the server's response to do other things - in this respect, "asynchronous" is somewhat like the term "modeless" in a dialog context (we previously discussed the difference between modeless and modal dialogs in Blog Entry #184).

At the heart of Ajax is an XMLHttpRequest object that represents an XML request using HTTP, quoting Microsoft, and that will serve as the middleman between the current document and the XML document we'll be requesting. The XMLHttpRequest object is today supported by all of the major (GUI, JavaScript-capable) browsers; the properties and methods of the XMLHttpRequest object vary somewhat on the Microsoft and Mozilla sides but the XMLHttpRequest members we'll be using - the onreadystatechange, readyState, and responseXML properties and the open( ) and send( ) methods - all have cross-browser support.

With no further ado, let's get to the tutorial code, which replaces the textual part of a p element with the content of an XML <data> element - nothing too earth-shaking, as befits an introductory tutorial. Here's the p element we'll be updating:

<p id="xmlObj">
This is some sample data. It is the default data for this web page.
<a href="data.xml" title="View the XML data." onclick="ajaxRead('data.xml'); this.style.display='none'; return false;">View XML data</a>
</p>


The p element presents "some sample data" followed by a View XML data link. Clicking the link sends users without JavaScript support to the data.xml document below via the link's href attribute:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <data>
    This is some sample data. It is stored in an XML file and retrieved by JavaScript.
  </data>
</root>


What you see above is what you'll see at the data.xml page: the beginning XML declaration, the root and data element markup, and the data element content will all be visible (the white space formatting may vary a bit depending on your browser).

For users with JavaScript support, clicking the View XML data link executes three statements:
(1) ajaxRead('data.xml'); calls an ajaxRead( ) function and passes thereto the string data.xml.
(2) A this.style.display='none'; style command zeroes out the link (reduces its area on the page to 0).
(3) return false; suppresses the link's default action (going to the data.xml page via the href attribute).

The ajaxRead( ) function creates a new XMLHttpRequest object and then uses that object to connect to the data.xml document. Here's the XMLHttpRequest constructor code:

<script type="text/javascript"><!--
function ajaxRead(file) {
    var xmlObj = null;
    if (window.XMLHttpRequest) {
        xmlObj = new XMLHttpRequest( ); }
    else if (window.ActiveXObject) {
        xmlObj = new ActiveXObject("Microsoft.XMLHTTP"); }
    else { return; }


XMLHttpRequest's Netscape/Mozilla support goes back to Netscape 6.x (from testing in the SheepShaver environment, I can verify that Netscape 6.2.3 supports it); its Microsoft support began with IE 7. However, the XMLHttpRequest "interface" - the package of properties and methods that is available to the XMLHttpRequest object - was actually first implemented by Microsoft in IE 5 for Windows. Microsoft called the object XMLHTTP back then and instantiated that object via the ActiveX framework as shown in the above code's else if clause - ActiveX is a can of worms we're not going to open but you can visit Microsoft's current ActiveXObject Object page here.

It follows from our discussion earlier that for most browsers, the code's if clause is operative: a new XMLHttpRequest object is created and given an xmlObj identifier.

Regarding the if condition, I'm not quite sure what the window.XMLHttpRequest expression represents; the definition offered at Microsoft's XMLHttpRequest Property page - Instantiates the XMLHttpRequest object for the window - seems dodgy, although a commenter yecril says, The description is incorrect ... [window.XMLHttpRequest] contains a reference to an XML HTTP Request Factory for HTML, whatever that means. Meanwhile, Mozilla doesn't list an XMLHttpRequest property in its DOM window Reference. In any case, a probe of the window.XMLHttpRequest return value reveals it to be browser-dependent - for example, it's [object XMLHttpRequest] with Firefox but it's function XMLHttpRequest() { [native code] } with Opera - typeof-wise, window.XMLHttpRequest is reported to be a function by the browsers on my computer excepting Safari, which says it's an object. But of course, what really matters is that the window.XMLHttpRequest condition converts to true for browsers that support the XMLHttpRequest object and to false for those that don't.

For any IE 5-6 for Windows users out there, the else if clause is operative: those guys correspondingly get a new XMLHTTP object, again with an xmlObj identifier and having access to the same basic properties and methods that an XMLHttpRequest object has. BTW, with IE 5.2.3 for Mac OS X - the final version of Internet Explorer for the Macintosh - window.ActiveXObject returns function ActiveXObject() { [native code] } and thus converts to true as an if condition but the xmlObj = new ActiveXObject("Microsoft.XMLHTTP"); line throws an Object doesn't support this action runtime error.

Finally, users without XMLHttpRequest/XMLHTTP support will exit the ajaxRead( ) function via the return; statement of the code's concluding else clause.

After the constructor block we have an xmlObj.onreadystatechange = function( ) { ... } function expression that we'll go through in detail later, but what actually happens next, execution-wise, is the call to the XMLHttpRequest open( ) method that follows the expression:

xmlObj.open("GET", file, true);

Contra the tutorial, the admittedly poorly named open( ) method does not open a connection to a server nor does it request a file; it merely initializes (sets values for) a request to a server. The open( ) method can take as many as five parameters: the first two are required, the latter three are optional.

(1) The first open( ) parameter sets the HTTP request method we'll be using: in this case, we want to GET our hands on a resource. Mozilla recommends that the parameter value be written in all-uppercase form, although I find that get works OK when using Firefox.

(2) The second open( ) parameter sets the request URL: in this case, we want to connect to the file=data.xml resource. For security reasons, the requested resource and the calling document must be in the same domain, that is, you can't use the open( ) method to link from 1.com/page.html to 2.com/page.xml.

(3) The third open( ) parameter is a boolean switch for specifying an asynchronous or synchronous request: true (the default) gives you the former and false gives you the latter - the preceding command's true argument can thus be removed but there's no harm in leaving it there. Curiously, the author alleges that synchronous won’t work in this case, and I couldn't think of why that might be; in the event, toggling the command's true argument to false slows down the document modification effect a bit when using Safari, Opera, and Chrome but does choke off the effect with Mozilla-based browsers (Firefox, Camino, Netscape 9) for reasons beyond my understanding.

The other two open( ) parameters relate to user authentication - there's no need for us to discuss them, so we won't.

We are at long last ready to send off our request for the data.xml document, an action appropriately carried out by a subsequent call to the XMLHttpRequest send( ) method:

xmlObj.send("");

For a GET request, the send( ) method shouldn't have an argument at all - see the Example on the aforelinked Microsoft window.XMLHttpRequest page - and xmlObj.send( ); works A-OK with Firefox, Safari, Opera, and Chrome. However, with older Mozilla-based browsers and also with Camino, xmlObj.send( ); throws a Not enough arguments error; per Mozilla's practice, I find that the error is reliably preempted by equipping send( ) with a null argument. I don't know where the author's use of an empty string literal for the send( ) argument comes from - Apple uses this syntax but doesn't comment on it - it quashes the Not enough arguments error with Camino and Netscape 9 but a Could not convert JavaScript argument arg 0 [nsIXMLHttpRequest.send] error was thrown when I tried it with Netscape 6.2.3.

We'll track and process the server's response in the following entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)