My work, my ideas, my faith, my life

True to Form

Altogether More Tractable

By Rex Goode

This post is for web developers who are familiar with the HTML, XML, and Javasript languages. Some of my usual readers won’t be interested. Feel free to read it anyway, but I didn’t make a big effort to start from the basics.
Of Ajax, epic character in the Trojan War, it was said by William Shakespeare in the voice of Agamemnon, comparing Ajax to Achilles, “You are as strong, as valiant, as wise, no less noble, much more gentle, and altogether more tractable (Troilus and Cressida).” I beg to differ.I am not talking about the old, standby cleaning products that people use. It’s a good brand. I’m also not talking about the hero of antiquity. I’m talking about a web development system called AJAX. It stands for Asynchronous Javascript and XML.

Using Agamemnon’s list, it is strong, perhaps violent, wise, and noble. I did not, however, find it to be gentle and least of all, tractable. Random House Dictionary says that “tractable” means “easily managed or controlled.” That has not been my experience with it.

I refer to AJAX as a development system because it is based in Javascript, but also employs XML (eXtensible Markup Language) and other web development technologies. Since it isn’t my purpose to explain all of this to non-techs, I’ll refrain from too much bringing all of my friends up to speed on what some of these things mean.

What I want to do is describe a simple example that I came up with, one that goes a little farther than other examples I have seen. Most AJAX examples you find on the web are about using it to manipulate just one element on a web page. For the needs of a WordPress plugin I have been developing, I needed it to manipulate four different web elements with one Javascript script.

It was trying to accomplish this that I encountered the AJAX intractability. Since I worked my AJAXity using three languages, I will address the intractability issue on three fronts: HTML, XML, and, uh,  XML.

HTML, XML, and HTML as if it were XML

When you write HTML code, you have tags in angle brackets (<>) along with attributes. For example:

<p align=center>Some text</p>

The HTML tag, P, for paragraph, has several possible attributes, including ‘align’. If you are just coding web pages in HTML, this is acceptable. To use good form, however, real programmers, supposedly, put the attribute value in single or double quotes, as in:

<p align=’center’>Some text</p>

Plain old HTML doesn’t mind if you leave out the quotes, as long as the attribute value contains no white space. Not so with trying to output HTML through AJAX as if it were XML. That’s because XML is unforgiving about such a lack of good form.

In fact, if you have any such lapse in form, such as leaving an attribute value unquoted, your attempt AJAXing will fail. You can get away with it if you’re trying to parse HTML as text instead of as XML. I know, it’s confusing.

Javascript

As unforgiving as XML is, Javascript is merciless when it comes to coding errors. Generally, without putting a ton of error handling into it, when it fails, it just fails and doesn’t tell you why. You make a change, and suddenly, what was working fine before isn’t working anymore and the reason is completely invisible.

Javascript has error-handling capabilities. I prefer the newer way, which is with the try-catch methodology. Basically, that means that you try something (a line or lines of code) within a try block. If any line of code within the try block has an error, it will throw an error that the catch block will catch and process. (See the example.)

try {
   document.write('hello');
} catch(err) {
   alert('Cannot write hello.');
}
There are no samples of this in the Javascript for the example I am presenting, so I can keep the code reduced. Just know that it’s good to put it in your code, especially if it mysteriously stops working (and it will).

Why Use AJAX?

The beauty of AJAX is that you can manipulate portions of a web page without reloading the entire page. You can define a block of a web page with an id and then use AJAX technology to change just that portion of the page. In the old days, if you wanted to change a section of a web page, you had to reload the whole thing. You could get away with something similar using frames or iframes, but they are more for putting things in a fixed size on your screen. With them, you are really loading a whole different page that shows in the same window as the main page.

Many times in my long history of doing web development, the idea of changing a section of the page without reloading the whole page would have worked well and simplified my work. I have known about AJAX for awhile, but keeping up with other projects has kept me away from learning it.

This last week, I took the time and want to share what I learned.

The Example

This example shows a page with a button that simply says, “Do It”.

If you click on that button, without reloading the entire page, you will see two new page elements appear.

 

Without AJAX, pushing the button would have had to go back to the server and reload the whole page. For something as small and insignificant as this, maybe it isn’t such a big deal. For a larger page with lots of other things going on, this has many advantages.

What It Did, Internally Speaking

The web page has four main elements in the body section—two headers, a paragraph section for errors, and the Do It button. Everything but the button is empty.

When a user clicks the button, a script written in Javascript is called that opens a request to an XML document. When the request is filled, the same Javascript catches it, receives the content of the XML document and parses one part into the first header and the other part into other header.

If there is an error in the XML document (remembering that XML is intractable), information about the error is loaded into the error section of the page.

The HTML File

The HTML file, test.html, includes the Javascript and the HTML code.

<html><head><title>Ajax Test</title></head>
<script type="text/javascript">
function ajtest() {
   var ajaxRequest = new XMLHttpRequest();
   ajaxRequest.overrideMimeType("text/xml");

   ajaxRequest.onreadystatechange=function() {
      if (
         ajaxRequest.readyState==4 &&
         ajaxRequest.status==200 ) {
         xmlDoc = ajaxRequest.responseXML;
         a = xmlDoc.getElementsByTagName("*");
         if (a.length == 2) {
            if (a[0].nodeName == 'parsererror') {
               txt = "<pre>";
               for(i=0; i<a.length; i++) {
                  txt = txt +
                        a[i].nodeName + '\n';
                  txt = txt +
                        a[i].textContent + '\n';
               }
               txt = txt + "</pre>\n";
               document.getElementById(
                    'AJAX_Error').innerHTML = txt;
            }
         }
         x=xmlDoc.getElementsByTagName("DIVPAGE");
         for(i=0; i<x.length; i++) {
            divname = x[i].attributes.getNamedItem(
                      'divname').value;
            switch(divname) {
               case "ONE":
                  txt = x[i].textContent;
                  break;
               case "TWO":
                  txt = x[i].textContent;
                  break;
               default:
                  txt = "";
                  break;
            }
            document.getElementById(
                divname).innerHTML=txt;
         }
      }
   }
   ajaxRequest.open("POST", "test.xml", true);
   ajaxRequest.setRequestHeader(
          "Content-Type", "text/xml");
   ajaxRequest.send();
}
</script>
<body>
<h1 id="ONE"></h1>
<h2 id="TWO"></h2>
<p id="AJAX_Error"></p>
<button onClick="ajtest();">Do It</button>
</body>
</html>

Within the body tag is the whole of the page as seen by the user. There is an h1 header with the ID of “ONE”, the h2 header with the ID of “TWO”, a paragraph for displaying any errors that happen, and the button definition, which includes a Javascript event handler to be called when the user clicks on the button.

<body>
<h1 id=”ONE”></h1>
<h2 id=”TWO”></h2>
<p id=”AJAX_Error”></p>
<button onClick=”ajtest();”>Do It
</button> </body>

Since the h1, h2, and p elements are all empty, the user sees only the button. Once a user clicks on “Do It”, the script contained within the <SCRIPT> start and end tags is called. The first thing it does is create an AJAX request object and specifies that it is expecting an XML document in return.

This second step was never mentioned as necessary in all of the examples I found, but I couldn’t get it to work without it.

var ajaxRequest = new XMLHttpRequest(); ajaxRequest.overrideMimeType(“text/xml”);

The next thing it does is create a function that will be called when the information is returned. This constitutes the bulk of the Javascript up to, but not including, the call to the ajaxRequest.open() function.

ajaxRequest.open(“POST”, “test.xml”, true);
ajaxRequest.setRequestHeader( “Content-Type”, “text/xml”);
ajaxRequest.send();

The open() function takes, as its first argument, the request method, which can be “GET” or “POST”. Get is somewhat limited in the kind and size of the information you can send via the open() function. Since this script isn’t sending any information, it doesn’t really much matter. The name of the document I am requesting is ‘text.xml’. It could have easily been to something written in any number of web development and scripting languages such as PHP, ASP, or HTML.

I chose XML because if you send it to a script that returns something other than XML, you have to work harder to parse it in the handler function. Javascript comes with some pretty useful XML parsing tools that I wanted to use.

I don’t think I needed to, but I sent a header specifying an XML document. Given the intractability of AJAX, I just left it in once I got it working. Someday I will figure out if I needed it or not, and why.

Finally, now that that the request is empty, it is sent to the server. When it is ready with a response, the function declared in the ajaxRequest.onreadystatechange attribute handles the response. The first thing it does once the response is ready is put the XML document into a Javascript variable that I can parse.

xmlDoc = ajaxRequest.responseXML;
Now, you don’t have to put the information that you retrieve directly onto the page. That was one of the first things I didn’t understand by reading all of the examples I could find online.

The other thing I didn’t understand, but now I do, is that you can send different parts of the response to different parts of the web page. You can take different parts of it and use the data to create and present something entirely different on the web page. However, to keep it simple for this article, I’m just going to parse the data and send it out to the two headers (h1 and h2) directly.

If there is an error in the XML document, I’m going to send information about it to the error section of the page. The error handling is contained in the following section of code. Basically, if the name of the first element of the document is “parsererror”, you know something is wrong with the XML code. Remember, it is intractable.

a = xmlDoc.getElementsByTagName("*"); 
if (a.length == 2) { 
   if (a[0].nodeName == 'parsererror') { 
         txt = "<pre>"; 
         for(i=0; i<a.length; i++) { 
                txt = txt + a[i].nodeName + '\n'; 
                txt = txt + a[i].textContent + '\n'; 
         } 
         txt = txt + "</pre>\n"; 
        document.getElementById('AJAX_Error').innerHTML = txt; 
   } 
}

The terminology that XML uses for XML code that is without errors is “well-formed”. XML code that is not well-formed is rejected by AJAX functionality. Putting this code in the Javascript ensures that I will know when I have XML on my hands that is not well-formed. The error section of the page will give pretty good information on the well-formedness of my XML document.

Normally, you don’t really want your web users to see errors on the pages they look at. That isn’t good form either. I would be more likely to put this error into an HTML comment that I could look at if things weren’t working rather than shock my users with my imperfections, not that I’m above doing that sometimes. I am putting it where I do in this example for your enlightment, dear reader.

Two lines of this code deserve special attention:

a = xmlDoc.getElementsByTagName(“*”);
and
document.getElementById( ‘AJAX_Error’).innerHTML = txt;

The first reads into an array (a), all of the elements of the XML document. The “*” in the function call indicates that I want all of them. When you get a parser error, you get two elements back and the first one is named “parsererror”.

The second line of code in the box above is the heart of the magic of AJAX. It finds the element on the web page, in this case, the paragraph (p) element that is identified as “AJAX_Error” and places into it whatever I want. What I want to place into it is the information I gleaned from the parser error generated by my misbehaving, or unwell-formed, XML.

You will see this getElementById thing later in the script when I go to fill up the two headers.

The XML Document

Before I show you this, let’s look at the content of the file, ‘test.xml’.

<?xml version="1.0" encoding="ISO-8859-1"?> 
<AJ> 
 <DIVPAGE divname='ONE'>One is the loneliest number</DIVPAGE> 
 <DIVPAGE divname='TWO'>Two can be as sad as one</DIVPAGE> 
</AJ>

My intention here is not to teach XML. Basically, the first line of this file specifies that it is, indeed, an XML document. Within the document are different levels of tag. In order for it to be well-formed, it must have a single, all-encompassing, top element, which I just happened to call, “AJ”. Call it anything if you are writing an XML document. All it has to do is encompass all other elements within it.

This simple XML document has only two elements, both named the same. Each one has a single attribute named “divname”. The value of divname for the first element is “ONE”, corresponding to the h1 tag in the HTML document with an ID of “ONE”. The second element has a divname value of “TWO” corresponding to the ID of the h2 element in the HTML document.

See those two sections of the two files side-by-side:

<h1 id=”ONE”></h1> <h2 id=”TWO”></h2>

<DIVPAGE divname=’ONE’>One is the loneliest number</DIVPAGE> <DIVPAGE divname=’TWO’>Two can be as sad as one</DIVPAGE>

 

 

 

 

Now, let me be clear. These are only the same as each other because I designed it that way. It made it easier for me to understand to give them the same names, respectively, not to mention easier to demonstrate. Unfortunately, when you do that, you might give the impression that they must be the same. They don’t.

The final piece of the Javascript I haven’t described is how I send the data from the two XML documents to their respective page sections.

x=xmlDoc.getElementsByTagName("DIVPAGE"); 
for(i=0; i<x.length; i++) { 
  divname = x[i].attributes.getNamedItem('divname').value; 
  switch(divname) { 
     case "ONE": 
         txt = x[i].textContent; 
         break; 
     case "TWO": 
         txt = x[i].textContent; 
         break; 
     default: 
         txt = ""; 
         break; 
  } 
  document.getElementById(divname).innerHTML=txt; }

The first and last statements in this block of code should be familiar by now. The code for handling XML document “not well-formed” errors used them. The one at the top gets an array of all elements named “DIVPAGE”. The last line puts the text created from those elements into the two different sections of the web page.

I do this for all DIVPAGE elements in a loop and send it to the right place on the page based on the value of the divname attribute, which I retrieve with the getNamedItem() function call.

If you are getting all of this, you might notice that I didn’t have to do the whole switch thing. I could have simplified this script like this:

x=xmlDoc.getElementsByTagName("DIVPAGE"); 
    for(i=0; i<x.length; i++) { 
        divname = x[i].attributes.getNamedItem('divname').value;     
        document.getElementById(divname).innerHTML=x[i].textContent; 
    }

The reason I did it with the switch construct is to allow for maybe processing the response differently depending on which divname I am working on.

I am using this entire methodology for a WordPress plugin I am working on. The plugin will allow a blog administrator to limit access to certain bbPress forums to certain users. The administration of this activity will be much faster for the adminstrators because they won’t have to wait for each little change to go through an entire reload of the page, which includes all of the WordPress dashboard menu, headers, and footers.

3 people like this post.

One Response to “True to Form”

  1. Rex Goode » Forum Restrict said:

    […] work, my ideas, my faith, my life « True to Form […]

Leave a Reply

If your comment is a support question, please post it at the forums.