Archive for October, 2006

Attempting AJAX

Monday, October 23rd, 2006

So, AJAX is one of the more recent causes of excitement in the web-based application delivery world. The first major site to feature AJAX (as far as I know) was Google’s gmail. Assuming that you are okay with writing tons of Javascript, it’s quite a nice way to spice up your application enough to make your users feel a little less like they’re using a web-based app.

I have to admit that I generally like to use the minimum of Javascript on my sites that can possibly work, because it usually doesn’t. Javascript is notorious for failing on various browsers and platforms with no specific rhyme or reason. Most often, it is because the application developer did not take the time to test and debug the Javascript on various browsers, or failed to use standards-compliant code and chose a single target browser (this more often happens when an application is targeted towards Microsoft Internet Explorer).

My rule of thumb is that Javascript should not be used unless there is some non-Javascript backup for the same functionality. Basically, Javascript may only be used to enhance the user interface; it cannot be used to drive the user interface.

We have a page that allows users to tick items off of a list. The list is pagenated, to it can be quite long. They can either tick them or un-tick them, and the page reflects the current status of each item. There is one big problem with this type of interface: the user expects to interact with a standard widget (the checkbox), but the page itself does not respond to checking or unchecking the checkbox: you have to submit a form. This basically won’t work because users are not going to tolerate having to check these items and then click a button, especially when moving from one page to another. They might also tick an item and then leave the page entirely. There is no way to stop them, and the only way to capture the event of ticking the checkbox is to use Javascript.

I am unhappy with the Javascript-only solution because it breaks down when the user’s browser does not have Javascript available. The user might not have Javascript available because of the browser (think lynx), or because they have turned off Javascript for security reasons, or because their Javascript implementation is buggy and isn’t going to work for some reason. Another approach is required.

My solution in the past was to make the checkbox into an image that looks like a checkbox, but it actually a link. That link points to the URL that selects (or de-selects) the item in question, which then re-displays the page with the proper status update. This works very well, except for the fact that the page view often re-sets itself back to the top of the page. That is inconvenient when you want to select multiple items from the same page, and you have to scroll down the page to see them.

This is a perfect example of when I have a non-Javascript solution working that could be significantly improved through the use of Javascript.

Enter AJAX.

If all the planets are aligned (i.e. the user has Javascript available and enabled, and it supports AJAX, and nothing else goes wrong), we can use some AJAX magic to improve the user experience.

AJAX is little more than a single (at least, from an AJAX developer’s point of view) very useful Javascript object called XMLHttpRequest. It’s job is to make an asynchronous HTTP request to some URL and provide the response either as text or as an XML document. If you elect to use the response as an XML document, then you can use the standard DOM methods to traverse everything.

I started out by consulting Mozilla’s AJAX:Getting Started page. It gives a fairly straightforward example of, well, getting started with AJAX. Using the information presented on that page, I was able to get something up and working relatively quickly. They had even listed the changes I would have to make in order to use the code under Microsoft Internet Explorer, so I figured I was covered when I went to test on MSIE.

Unfortunately, there’s a relatively large caveat when using MSIE up through version 6 when working with XML: the document.getElementsByTagName function is not namespace-aware. That means that those of us who came out from under the non-namespace-using rock several years ago have to deal with some pretty stupid code in order to work around it.

At this point, AJAX pros are saying to themselves “why doesn’t this guy just use one of the dozen or so cross-platform AJAX libraries that are out there — then he won’t have this problem”. Well, I’ll tell you: because I wanted to solve the problem myself in order to understand what was going wrong. It did take quite a while, and I ended up using information presented on Apple’s Dynamic HTML and XML: The XMLHttpRequest object. This was the only place where I saw any mention of MSIE’s failure to support namespaces.

Working around non-namespace-aware Javascript is pretty ugly. Under normal circumstances, one would simply call document.getElementsByTagName and pass the “local name” of the element to that function. You’d get an array of nodes back and everything would be fine. But, since MSIE sees “foo:bar” as the local name (instead of just “bar”), you’d have to change your code to look for “foo:bar”. But, that wouldn’t work in browsers that are namespace-aware, and it’s difficult, if not impossible, to tell at runtime which way a browser will behave.

So, I was forced to implement my own function that loops through the children of a particular node and looks for matching elements. :(

It occured to me just now that I could probably get away with making two calls: one that uses the preferred method, and then, if the call returns no nodes, another that calls the same method with the namespace attached. The only problem with this option is that you have to know the text of the namespace that is being used. Typically, you only have to deal with the namespace URI instead of the actual value being used (such as “foo” in the example above). In this case, I’ll have to hard-code the namespace into the Javascript, which is non-ideal. My existing solution has no such restrictions, so I’ll probably keep it for the time being.

A special thanks to the MSIE team for once again stepping outside of the standard (which, in all fairness, may or may not have existed at the time of implementation) and spicing up my day.

Now, time to test on MSIE 7. And Opera. And Safari….