Registered Ajax Responders Not Responding Properly
Ajax Fundamentals
If you use the Prototype Javascript library and you chain your Ajax calls together at times, you may have run into the issue that I just dealt with regarding your registered responders not responding correctly! Since I spent more time than I care to share trying to figure out why my global responders weren't working like I thought they should, I thought I'd share what I learned. Hope it saves somebody some time! :)
In my application, I am allowing a user to upload a data file. When the upload of the file is complete, I then need to kick off a series of things to occur, and I want to update a DIV with the current status of each call as they happen. The first call is to validate the uploaded file, so I write an Ajax simple request that tells the server where the file was uploaded and what kind of file it is supposed to be. This call will either return a true or false, depending on whether the file passed or not. If it failed, I want to tell the user that the file was bogus and cease any further processing. If it passed, I want to kick off another Ajax simple request that tells my app to go ahead and proceed with step 1 of the file processing. That call will return success or failure along with status messages, and then will kick off the third step in the processing.
Now, the way we "connect", or "chain" these calls together is by taking advantage of the fact that our library knows when a call is finished. When we write the JS for call 1, we tell it "when you receive a response from the server, pass that response on to Call 2 for evaluation". Call 2 is written to check the success status, and if all is well will make an Ajax simple request which itself has been told to pass its results on to Call 3. Here's an abbreviated example of what I'm talking about (some code ommitted for brevity):
See how they're all connected? Chain Chain Chaaaaaaainnnnnn... yeah.
After much experimentation, it occurred to me that perhaps even though the responder was global, maybe I needed to be concerned with manually 'watching' the active request count variable. I don't understand why I SHOULD have to, but that did turn out to be the solution. Here is the properly working responder registrations:
Notice the only difference is in the onComplete function...I am 'watching' the activeRequestCount variable (which as you may have guessed is simply a counter telling us how many requests are currently not yet finished) and conditionally hiding my responder.
Doug out :0)
Prelude
You may not be familiar with some of the terms I have used already, or some that I will use. If you feel you already have a good grasp on the lexicon surrounding Ajax and JS libraries, skip ahead to The Scenario; but if not, then allow me to clear up some of the fog before we press on. Please excuse me if I spend time on things that you may feel are "common knowledge", but in my experience there really is no such thing and I want to make sure every reader is thinking in the same context.The Basic Nutshell of Ajax Chaining
In Prototype and other similar libraries, an Ajax call is typically of one of two flavors: simple request, and an update request.Simple Requests
A simple request is one in which you ask your JS to make an http call to the server and hand you back the results that were delivered, whatever they be. At that point you will have written more Javascript to actually deal with those results manually. For example, let's say you display a select list containing possible food categories to your user. When the user selects a category, an Ajax request is made passing in the selected category, and a JSON representation of a record set containing foods in that category is returned. That JSON object is handed off to another function you wrote which will 'walk' through the foods and populate yet another select list with the specific items.Update Requests
An update request is one in which you are asking your JS to make an http call to the server and stuff the results, whatever they be, directly into a DOM element (a DIV tag, a SPAN tag, etc.). Let's make a slight change to the example cited above. In this scenario, we already have a DIV tag in our html that we have designated as the place where our select list should appear. So, instead of having our server code return a raw JSON representation of the data, we write our server code to produce the HTML for the fully populated select list ("<select name='selFoods'><option value='1'>Crescent Rolls</option><option value='2'>Dog Biscuits</option>....</select>"). It is this string that our Ajax call receives, and this returned value is stuffed directly in to the DIV tag we designated as the recipient. Make sense?Registering Responders
It is quite typical (and useful) to show to your users some kind of "working" image to indicate that the Ajax call is in progress. We may also wish to disable certain items on the user interface while calls are in progress, or overlay an opaque div to prevent the user from clicking anything. The thing we want to do and/or display while an Ajax call is in progress is what we refer to as our "Responder". Within our Javascript, we will tell our library something along the lines of "hey, anytime an Ajax call is created (started), I want you to do this; and anytime you see an Ajax call finish, I want you to do this". The act of telling our library what we want to happen automatically regardless of the Ajax call is called "registering responders". You define (register) them one time, and they just work. :)Why Would I Ever Want to Chain My Calls?
I'm glad I asked! Let me just give you a working example to help illustrate why we might do this on occasion, and how we do it.In my application, I am allowing a user to upload a data file. When the upload of the file is complete, I then need to kick off a series of things to occur, and I want to update a DIV with the current status of each call as they happen. The first call is to validate the uploaded file, so I write an Ajax simple request that tells the server where the file was uploaded and what kind of file it is supposed to be. This call will either return a true or false, depending on whether the file passed or not. If it failed, I want to tell the user that the file was bogus and cease any further processing. If it passed, I want to kick off another Ajax simple request that tells my app to go ahead and proceed with step 1 of the file processing. That call will return success or failure along with status messages, and then will kick off the third step in the processing.
Now, the way we "connect", or "chain" these calls together is by taking advantage of the fact that our library knows when a call is finished. When we write the JS for call 1, we tell it "when you receive a response from the server, pass that response on to Call 2 for evaluation". Call 2 is written to check the success status, and if all is well will make an Ajax simple request which itself has been told to pass its results on to Call 3. Here's an abbreviated example of what I'm talking about (some code ommitted for brevity):
function Call1(){
new Ajax.Request(validateUploadURL,{parameters:params,method:'post',onSuccess:Call2});
}
function Call2(response){
var objRetval = response.responseJSON;
if(!objRetval.success){
$('status').update(objRetval.msg);
return;
} else {//call successful! carry on
new Ajax.Request(fileProcess1URL,{parameters:params,method:'post',onSuccess:Call3});
}
}
function Call3(response){
var objRetval = response.responseJSON;
if(!objRetval.success){
$('status').update(objRetval.msg);
return;
} else {//call successful! carry on
new Ajax.Request(fileProcess2URL,{parameters:params,method:'post',onSuccess:TheEnd});
}
}
function TheEnd(response){
var objRetval = response.responseJSON;
$('status').update(objRetval.msg);
}
new Ajax.Request(validateUploadURL,{parameters:params,method:'post',onSuccess:Call2});
}
function Call2(response){
var objRetval = response.responseJSON;
if(!objRetval.success){
$('status').update(objRetval.msg);
return;
} else {//call successful! carry on
new Ajax.Request(fileProcess1URL,{parameters:params,method:'post',onSuccess:Call3});
}
}
function Call3(response){
var objRetval = response.responseJSON;
if(!objRetval.success){
$('status').update(objRetval.msg);
return;
} else {//call successful! carry on
new Ajax.Request(fileProcess2URL,{parameters:params,method:'post',onSuccess:TheEnd});
}
}
function TheEnd(response){
var objRetval = response.responseJSON;
$('status').update(objRetval.msg);
}
See how they're all connected? Chain Chain Chaaaaaaainnnnnn... yeah.
The Scenario
In my scenario, I have a file upload process that is composed of three different Ajax requests, all chained together in a conditional, synchronous fashion (I know there are other ways to approach it, but this is the one that fit my needs the best). I have registered global responders to show/hide an animated spinner to indicate when a request has started and finished (I 'show' it when the request starts, I 'hide' it when its finished). Now, in my mind, these global responders should toggle that gif every time a request starts or stops, so in this scenario, it should show/hide three different times. But, that isn't how it worked. The gif would show during the initial call, and hide after that call was finished; Then it never showed again, despite the fact that there were multiple additional calls made! Here is how I registered my responders: Ajax.Responders.register({
onCreate: function() {
showUploadWorking();
},
onComplete: function() {
hideUploadWorking();
}
});
onCreate: function() {
showUploadWorking();
},
onComplete: function() {
hideUploadWorking();
}
});
After much experimentation, it occurred to me that perhaps even though the responder was global, maybe I needed to be concerned with manually 'watching' the active request count variable. I don't understand why I SHOULD have to, but that did turn out to be the solution. Here is the properly working responder registrations:
Ajax.Responders.register({
onCreate: function() {
showUploadWorking();
},
onComplete: function() {
if(Ajax.activeRequestCount == 0){
hideUploadWorking();
}
}
});
onCreate: function() {
showUploadWorking();
},
onComplete: function() {
if(Ajax.activeRequestCount == 0){
hideUploadWorking();
}
}
});
Notice the only difference is in the onComplete function...I am 'watching' the activeRequestCount variable (which as you may have guessed is simply a counter telling us how many requests are currently not yet finished) and conditionally hiding my responder.
Doug out :0)
Subscription Options
You are not logged in, so your subscription status for this entry is unknown. You can login or register here.
Re: Registered Ajax Responders Not Responding Properly
Ajax.Request.prototype.respondToReadyState() does not call onSuccess/onFailure for registered responders.
It does call this.options['on' + ('Success' or 'Failure' depending upon status)] correctly.
onComplete is called for both 'this' and registered responders.
It does call this.options['on' + ('Success' or 'Failure' depending upon status)] correctly.
onComplete is called for both 'this' and registered responders.
Posted by ccna voice on February 28, 2010 at 11:51 PM
Re: Registered Ajax Responders Not Responding Properly
I have never heard about Ajax. What is the function of this one?
Posted by dawid2011ed on January 24, 2011 at 10:14 PM
Re: Registered Ajax Responders Not Responding Properly
Good and very reliable post. Thanks a lot.
Posted by Paul on March 1, 2011 at 6:13 AM


