So, I am going to rewrite our JavaScript system, we are moving from Prototype to jQuery. We have loading AJAX requests that fire when certain events of an element occur, in the example below this is a new event in the calendar, but this happens elsewhere.
The problem I get is that when the event fires, sometimes two AJAX requests are executed. The first returns the correct value, but (as you can see) it still talks about processing, it never returns the success message that my JavaScript requires. The second query returns the correct result and ends correctly.
The problem is that our jQuery screen locker is configured to prevent user input during heavy AJAX requests, obviously because there still exists an AJAX request that never unlocks. If I refresh this screen, everything will work as desired.
Can anyone shed some light on why this behavior occurs.
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request.png
EDIT
"that fire when certain events of an element occur is a key phrase, I think. Provide some information about how you set your events. Maybe it fires twice because you have several handlers installed? - Igor Zinoviev
Well, the fact is that when I delete an update, the problem usually solves itself, so I'm not sure how this can be a problem with the handler, here is the event handler that we usually use to change the selection field.
$("#my_select","#context").change(function(){ // uz_ajax is a wrapper function, keeps most of the same functionality as $.ajax() uz_ajax({ target:"#my_target", data:{ module:'my_module', controller:'my_controller', action:'my_action', id:$(this).val(), ajax:'' } }); });
The problem is that I have no idea how to replicate the problem, so I don’t know if the event is fired multiple times or requested by AJAX twice.
EDIT 2
If you reload items that are related, change events can be triggered recursively ... We really need to see more code (what do you do for ajax call success, etc.) - RedSquare
Thanks redsquare, on a successful AJAX request, I usually apply the response (usually HTML <option> s) to the target. I never cause a change to an element that launched AJAX, but sometimes I cause a change to the target element to allow cascading AJAX requests. If this were a problem, is this, of course, all the time? My uz_ajax wrapper function uz_ajax below:
var ajax_count = 0; var ajax_response = null; function uz_ajax(options) { // set default options var defaults = { async: true, type: "GET", data: {}, url: "/", cache: false, force_change: true, highlight: true, action: "normal", dataType: "html", selected: { value: null, disabled: false } }; // merge the passed options with the defaults var options = $.extend(defaults, options); // start the jQuery ajax method $.ajax({ async: options.async, type: options.type, url: options.url, data: options.data, beforeSend: function() { // we only want to block the screen on the first pass if(++ajax_count==1) { $.blockUI({message:'Loading data, please wait'}); } }, success: function(responseText) { if(options.target!==undefined) { // if target isn't an array, make it one if(!$.isArray(options.target)) { options.target = new Array(options.target); } var targets = options.target; for ( var i in targets ) { console_info("uz_ajax() --> Applying contents to "+targets[i]); switch(options.action) { case "normal": if($(targets[i]).is("input")) { $(targets[i]).val(trim(responseText)); } else { $(targets[i]).html(trim(responseText)); } break; case "selected": // preserve the current target value (eg list of options), but // set the selected value to the ajax response console_warn("Changing selected value of "+targets[i]+" to '"+responseText+"'"); // trim the response so we don't get any smarty induced errors such as ' 7' $(targets[i]).val(trim(responseText)); break; } // set selected value if(options.selected.value!=null) { $(targets[i]).val(options.selected.value); } // highlight the target // we don't want to highlight the target if it a hidden input, as this will force a .show( if($(targets[i]).attr('type')!='hidden' && options.highlight===true) { $(targets[i]).effect("highlight",{},2000); } // force the target to change if(options.force_change===true) { $(targets[i]).trigger("change"); } /* rebind certain elements that do not use conventional events */ /* We probably need to get all of these rebinds in a single function */ createDatePickers(targets[i]); } } else { ajax_response = responseText; console_warn("uz_ajax -> no targets specified"); // Well... we have no element to target, we need to return the value instead // of course if we return here we're going // we probably also need to check the ajax count as this will be the last executed part before we return } }, complete: function () { /* if all ajax requests have completed, unblock screen */ if(--ajax_count===0) { $.unblockUI(); /* could use this callBack to return a value *dun dun duuuuun* */ if (options.ajaxComplete) { options.ajaxComplete(ajax_response); } } }, cache: options.cache, dataType: options.dataType }); }
another way to stop multiple ajax requests is to heck jQuery.active before calling. jQuery supports the internal calculation of live ajax requests using this property. - redsquare
I will consider this.
EDIT 3
So this is the result of $ ('element'). data (), but I can’t understand what he is trying to say if this means that there are two bindings to it. If so, how do I know what these bindings are and why they both do not fire when the event fires.
alt text http://archive.ilmv.co.uk/images/firebug-jquery-data-events.png
EDIT 4
Here is another screenshot of the problem, this time in a different place on the system. The green arrow is the element that launches three ajax requests, not firebug, as there are six, and that they connect and divide timestamps to milliseconds?
Triple triples are those that are not yet completed, the bottom three return the correct result.
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v2.png
EDIT 5
The figure below shows what happens when the selection field changes, it raises three different ajax requests.
I managed to do some more debugging, and I can tell you the following:
- The problem arises no matter how many ajax requests initial element calls
- The problem arises no matter what plugins are used
- This event is definitely only fired once
- The uz_ajax wrapper function is run only once per target (see firebug console, "Line 29: uz_ajax ()".
- I added
console.info for each of the jquery $.ajax() handlers to find out what to shoot and when, notice how the only callback is to run beforeSend() .
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v3.png
EDIT 6
So, after @redsquare suggested using console.trace() via Twitter to find out “where the second event occurs”, as I always supported, I’m sure that there are no two events, so I put the trace in the $.ajax() method $.ajax() , this is what happened:
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v4.png
As you can see, I get a duplicate ajax request task, even if the $.ajax() method is run only once, again the timestamps are identical. Am I encountering an error with jQuery?
EDIT 7
This also happens in StackOverflow!
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v5.png