Saturday, March 27, 2010

A little hack on AJAX timing

Say you need to initialize a web/app page with data dynamically loaded from some server by a Javascript module written with jQuery. Often, the problem encountered would be the pacing. That is, the events in the script don't necessarily take place in the same order as your code indicated. Here's an example that illustrates the evilness:

data = someModule.AjaxFetch(); // loading...
alert(data.item1); // Oh no, executed before AjaxFetch() has returned, undefined!

The typical solution is passing a callback function to the AjaxFetch() method. I don't know about you, but leaving that callback-function argument always makes me feel itchy(I'm a big Python fan, so doubt not about my awareness of the benefit of having the flexibility. After all, what's the point of modularization if I have to call a method from module A in module B?). It could be worse, what if the Ajax module doesn't provide the callback slot you needed?

The other possible solution is using some kind of delay function, pausing the script for some time and hope that the communication would be finished by then. Obviously this is too lousy for a reasonable programmer.

Here's what I came up today.

data = someModule.AjaxFetch();
$(document).ajaxComplete(function(){
    $(document).unbind($.ajaxComplete);
    alert(data.item1);
    // some more useful and complex code here.
});

The trick is to take advantage of $.ajaxComplete() provided by jQuery and unbind this event immediately after it happens for the first time.

The reason to unbind doesn't seem obvious at the first look. Here it is: $.ajaxComplete() listens to all kinds of Ajax communication conducted by jQuery. If the code in its call back involves more Ajax events, the call back will be called again, which is usually not an expected behavior!

Happy AJAXing!

No comments: