reptile7's JavaScript blog
Wednesday, June 08, 2011
Introductory Ajax Laboratory
Blog Entry #217

Having deconstructed the XMLHttpRequest script code of HTML Goodies' "How to Develop Web Applications with Ajax: Part 1" tutorial over the last two entries, we are ready to put it into action. Our specific goal is to replace the (highlighted in yellow below) of the ajax.html document's id="xmlObj" p element

<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');'none'; return false">View XML data</a>

with the textContent of the data.xml document's data element

    This is some sample data. It is stored in an XML file and retrieved by JavaScript.

which we will access via an XMLHttpRequest object's responseXML return.

I respectively place the tutorial's ajax.html and data.xml documents in separate TextEdit files and then upload those files to my EarthLink server space. I navigate to the ajax.html page and click the View XML data link. In the event:

• The data element textContent is written to the xmlObj p element with Opera and Opera alone.

• With all of the other XMLHttpRequest-supporting browsers on my computer, the View XML data link does at least disappear, but the p element's

This is some sample data. It is the default data for this web page.

string remains in place and an xmlObj.responseXML is null (or equivalent) error is thrown.

So, I go back and take a closer look at Mozilla's description of the responseXML property:
Returns a Document containing the response to the request, or null if the request was unsuccessful, has not yet been sent, or cannot be parsed as XML or HTML.
In their various XMLHttpRequest examples, Mozilla, Microsoft, and Apple all test the XMLHttpRequest status property, which returns the HTTP status code of the server response, after checking the request's readyState:

if (http_request.readyState == 4) {
    if (http_request.status == 200) { // If the response is OK...
        ... }

I precede the updateObj( ) function call with a window.alert(xmlObj.status); command and rerun the tutorial code; an alert( ) box displaying 200 duly pops up, so we can safely conclude that the xmlObj.responseXML is null error isn't resulting from an unsent or unsuccessful request.

The XMLHttpRequest object has a responseText property that returns a requested file as one big string; a corresponding window.alert(xmlObj.responseText); command pops up an alert( ) box displaying the intact data.xml document - the XML declaration, the root and data elements, even the white space formatting -

[The xmlObj.responseXML return]

so we are getting our hands on the data.xml data, just not in the form that we want it.

Ah, but what about the cannot be parsed as XML business? At the end of the Object Methods section of Apple's "Dynamic HTML and XML: The XMLHttpRequest Object" article is an all-important note:
Note: It is essential that the data returned from the server be sent with a Content-Type set to text/xml. Content that is sent as text/plain or text/html* is accepted by the instance of the request object; however, it will only be available for use via the responseText property*. [*We'll see below that this is no longer true.]
The XMLHttpRequest object has a getResponseHeader( ) method that [r]eturns the string containing the text of the specified header. Upon preceding the updateObj( ) function call with a window.alert(xmlObj.getResponseHeader("Content-Type")); command, the resulting alert( ) box displays text/plain; in corroboration, a HEAD request for my data.xml file at Rex Swain's HTTP Viewer also returns a text/plain Content-Type. It would seem that the server doesn't see the data.xml document as a document at all, XML or otherwise.

To deal with this type of contingency, Netscape implemented in Netscape 7 an XMLHttpRequest overrideMimeType( ) method for overriding the MIME type returned by the server. In illustration, Mozilla's "Getting Started [with Ajax]" article features a Step 4 – Working with the XML response example whose httprequest_test_xml.html document contains the following block of instantiation code:

if (window.XMLHttpRequest) { // Mozilla, Safari,...
    http_request = new XMLHttpRequest( );
    if (http_request.overrideMimeType) {
        http_request.overrideMimeType("text/xml"); } }

I am gratified to report that deploying a corresponding conditional in the ajax.html document eliminates the xmlObj.responseXML is null error and gives a functioning demo with Firefox, Safari, Chrome, and Camino; the use of application/xml for the overrideMimeType( ) argument also works.

Opera supports the overrideMimeType( ) method but doesn't need it in this case - evidently there's something in the Opera code (perhaps in its JavaScript engine) that says "It's XML" when an .xml file is called on.

responseText extraction

There's just one little problem with our use of the overrideMimeType( ) method: IE doesn't support it. However, the demo can be made to work for IE users by making recourse to the responseText return.

/* This conditional has been successfully tested with Netscape 7.02, which supports the overrideMimeType( ) method,
and with Netscape 6.2.3., which does not. */
if (xmlObj.responseXML) {
    updateObj("xmlObj", xmlObj.responseXML.getElementsByTagName("data").item(0); }
else {
    var datastart = xmlObj.responseText.indexOf("data") + 5;
    var dataend = xmlObj.responseText.indexOf("</data>");
    updateObj("xmlObj", xmlObj.responseText.substring(datastart, dataend)); }
/* Neither Netscape 7.02 nor Netscape 6.2.3 supports the textContent property. */

If the server reports a non-text/xml Content-Type that cannot be overridden with the overrideMimeType( ) method, then the xmlObj.responseXML condition of the preceding code's if clause returns null by default and converts to false; subsequently, the else clause locates and extracts the data element content via the String object's indexOf( ) and substring( ) methods, respectively.


You can try it all out in the div below - click on the View XML data link to see if you are Ajax-ready. If you're a 'sans-JavaScript' user, then clicking the link will display a screen shot of a corresponding data2.xml page as rendered by Firefox in a new window.

Developing Web Applications with Ajax

This page demonstrates the use of Asynchronous Javascript and XML (Ajax) technology to update a web page's content by reading from a remote file dynamically -- no page reloading is required. Note that this operation does not work for users without JavaScript enabled.

This is some sample data. It is the default data for this web page. View XML data

(To fend off possible support- and network-related errors, Mozilla, Microsoft, and Apple place parts of their example code in the try clauses of try...catch statements. The tutorial author doesn't do this, and I don't either in my demo - maybe I should.)

In the name of completeness: When the data element content is loaded into the xmlObj p element, the leading and trailing white space of that content is entirely discarded by the (Ajax-supporting) browsers on my computer excepting Opera, which discards the leading white space but pastes in the trailing white space's two space characters.

Retrieving HTML

Right before the tutorial's concluding That’s all there is to it section the author throws out an interesting possibility:
If you wanted to update an object with HTML instead of just plain text, you could also use
document.getElementById(obj).innerHTML = data;
Presumably he means for that HTML to be fabricated in the current document, but the question arises: Can we use an XMLHttpRequest object to GET a remote HTML document? That we can. The responseXML return for such a document will be null and thus we won't be able to walk that document's DOM tree, but we can definitely use the responseText property in conjunction with String object methods to grab what we want in the document as shown in the responseText extraction section above.

November 2016 Update:
The responseXML operation will recognize an HTML document as an [object HTMLDocument] if the responseType property of the XMLHttpRequest object is set to document just before the open( ) initialization - no overrideMimeType( ) action is required. In this regard, the above demo actually extracts the text of a
<data1 style="display:none;"> ... </data1> element placed near the beginning of the body of the previous post.

The author has also written "How to Develop Web Applications with Ajax: Pt. 2", "Developing Web Applications with Ajax, Pt. 3", and "Developing Web Applications with Ajax, Pt. 4" tutorials; we won't be discussing them, but by all means read through them if this sort of thing is your cup of tea.

Moving on in HTML Goodies' Beyond HTML : JavaScript sector, we will in the following entry begin with some 'quick takes' and then take up the sector's "Hovering HTML Windows and Animated Hovering Using JavaScript" tutorial.


Comments: Post a Comment

<< Home

Powered by Blogger

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