25

We use jQuery's global ajaxError() handler to alert the user of any AJAX failures:

$(document).ajaxError(function() {  
    $("There was a network or server error. Please try again later.").dialog({  
        title: "Error",  
        modal: true,  
        resizable: false,  
        buttons: { 'Ok': function() { (this).dialog("close"); } }  
    });  
});  

Unfortunately, this global error handler also fires if the user leaves the page before it finishes loading. Here are the steps to reproduce the error:

  1. User visits Page A, which includes elements that load via AJAX.
  2. AJAX elements on Page A begin loading.
  3. User clicks link to visit Page B before AJAX elements on Page A have finished loading.
  4. The error dialog box appears briefly before the browser redirects to Page B.

Any idea how we can get ajaxError() not to trigger when the error is directly caused by the user visiting a new page?

UPDATE: Here's my code now, after incorporating the suggestions in the comments:

// I added a 3 second delay to our error dialog, enough time
// for the user to leave for a new page:
$(document).ajaxError(function() {
    setTimeout(my_error_handler, 3000);
});

// Warn user before leaving page if AJAX is still loading.
// Not sure I'll keep this:
$(document).ajaxStart(function() {
    ajaxing = true;
});

$(document).ajaxStop(function() {
    ajaxing = false;
});

window.onbeforeunload = function() {
    if (typeof(ajaxing) != 'undefined' && ajaxing) {
        return "Page elements are still loading!";
    }
};
richardkmiller
  • 2,902
  • 3
  • 31
  • 29

2 Answers2

16

Well yes, if the user navigates to another page, the xhr will abort, which is, in effect, an unsuccessful communication. A solution would be to register a listener for the onbeforeunload event, and unbind ajaxError there, basically saying: the user is about to leave the page, so i do not wish to be informed of the ajax errors that might follow.

Some sites, though, like GMail, do the other way around: if you try to navigate away from the page while there are still some ajax requests pending, it gives you an prompt that says you've got some processes still running, and lets the user decide whether to stay on the site until the request has finished, or to go ahead and navigate away.

David Hedlund
  • 128,221
  • 31
  • 203
  • 222
  • 2
    GMail approach is far better! – TheVillageIdiot Dec 15 '09 at 09:04
  • 2
    well yes, if you must have a general catch-all approach to it, i suppose that's what i'd prefer as well. although i'd like it way more if a flag was passed to the function making the ajax call, determining whether the current request was critical or not. i.e. if the request is just a session keep-alive, or a checking for new messages, or something, you might want to let that abort silently. – David Hedlund Dec 15 '09 at 09:09
  • David, thanks for the suggestion. I haven't yet tested which browsers support onbeforeunload, but it's working well on FF 3.5 so far. I also added a 3 second delay to the error dialog (a suggestion from a previous comment that appears to be deleted now.) – richardkmiller Dec 16 '09 at 07:30
  • 2
    Sometimes onbeforeunload fires after ajaxError. For example in chrome, hitting the back button while a request is pending will error first, then window.onbeforeunload fires. – Ross Sep 23 '11 at 19:16
  • how to know whether there are still some ajax request pending when page navigate away? define a global variable to remember it? Is there a better way to do it? – hiway Dec 08 '13 at 10:44
10

Based on David Hedlund's response above here's the code that works for me:

//enable global ajax error handling
$(document).ajaxError(function (event, request, settings) {
    //your error handling code here
});

//user leaving page so ignore any unfinished ajax loads
$(window).bind('beforeunload', function () {
    $(document).unbind('ajaxError');
});

I got the 'ajaxError' spec from the comments section of jquery ajaxError documentation. I had to bind beforeunload to $(window) in order to support chrome (IE was working fine with document). .ajaxError didn't fire when I was binding to $(window) so this is why I have this window/document solution.

Alex
  • 9,250
  • 11
  • 70
  • 81