29

Branching off of questions like this one, I'm looking to wrap jQuery's $.ajax() method such that I can provide error handling in one location, which would then be used automatically by all of an application's remote calls.

The simple approach would be to simply create a new name, similar to how $.get() and $.post() implement facades to $.ajax(). However, I'm hoping to reuse the name $.ajax(), such that we can keep the rest of our code using the standard jQuery syntax, hiding from it the fact that we've added our own error handling. Is this practical and/or good to achieve, or possibly a horrible idea?

EDIT: The responses so far indicate .ajaxError() is the way to go. I know this will catch 400 and 500 level errors, but is there a way (with this event handler or otherwise) to catch 302 redirects as well? I'm trying to handle responses that are redirecting to a login page, but we want to intercept that redirect when it's an XHR request, allowing the user to cancel the action instead of forcing them forwards automatically.

Community
  • 1
  • 1
Marc L
  • 2,064
  • 1
  • 19
  • 12
  • On a side note, responses to non-logged-in AJAX requests should probably return 401 rather than 302. Food for thought anyway. – gtd Jan 12 '13 at 18:31

5 Answers5

36

You might want to look at $.ajaxError.

$(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownError) {
  alert("There was an ajax error!");
});

jQuery provides a whole bunch of other ways to attach global handlers.

To answer your edit, you can catch successful ajax requests with $.ajaxSuccess, and you can catch all (successful and failed) with $.ajaxComplete. You can obtain the response code from the xhr parameter, like

$(document).ajaxComplete(function myErrorHandler(event, xhr, ajaxOptions, thrownError) {
  alert("Ajax request completed with response code " + xhr.status);
});
kprobst
  • 16,165
  • 5
  • 32
  • 53
sje397
  • 41,293
  • 8
  • 87
  • 103
  • @Marc L: edited to match your extra info. Also, you might find this interesting: http://stackoverflow.com/questions/199099/how-to-manage-a-redirect-request-after-a-jquery-ajax-call – sje397 Dec 03 '10 at 03:01
  • 3
    Try `$(document).ajaxError(…);` - using `$.ajaxError(...)` did not work for me. – ripper234 Nov 27 '11 at 12:18
  • This does not catch 302/redirects :( - great solution otherwise! – OverMars May 07 '20 at 22:24
3

jQuery has a handy method called $.ajaxSetup() which allows you to set options that apply to all jQuery based AJAX requests that come after it. By placing this method in your main document ready function, all of the settings will be applied to the rest of your functions automatically and in one location

$(function () {
    //setup ajax error handling
    $.ajaxSetup({
        error: function (x, status, error) {
            if (x.status == 403) {
                alert("Sorry, your session has expired. Please login again to continue");
                window.location.href ="/Account/Login";
            }
            else {
                alert("An error occurred: " + status + "nError: " + error);
            }
        }
    });
});

Reference: https://cypressnorth.com/programming/global-ajax-error-handling-with-jquery/

SHIBIN
  • 397
  • 3
  • 5
  • I think this is better over ajaxError() as there's no need to bind the listener to the DOM and makes more sense when you say global. – Wancieho Jul 29 '18 at 10:26
  • 1
    @Wancieho **see** [Global callback functions should be set with their respective global Ajax event handler methods—.ajaxStart(), .ajaxStop(), .ajaxComplete(), .ajaxError(), .ajaxSuccess(), .ajaxSend()—rather than within the options object for $.ajaxSetup().](http://api.jquery.com/jQuery.ajaxSetup/) **AND** [As of jQuery 1.9, all the handlers for the jQuery global Ajax events, including those added with the .ajaxError() method, must be attached to document.](https://api.jquery.com/ajaxError/) – Mavelo Sep 08 '18 at 20:07
  • Apologies for ugly formatting, can only do so much in a comment – Mavelo Sep 08 '18 at 20:23
2

Actually, jQuery provides the hook, .ajaxError() just for this purpose. Any and all handlers you've bound with $ajaxError() will be called when an ajax request from page completes with an error. Specifying a selector allows you to reference this inside of your .ajaxError() handler.

To use it to handle all ajax request errors on the page and use this to point to document, you could do something like this:

$(document).ajaxError(function(event, request, settings){
   alert("Error requesting page: " + settings.url);
});
Alex
  • 64,178
  • 48
  • 151
  • 180
  • To clarify, ajaxError handles ALL ajax failures, not just those that match the selector. Using a selector only allows you to use the `this` keyword inside the callback to refer to that element. – David Tang Dec 03 '10 at 02:44
1

In some cases you might want to do global error handling before your local error handling function gets called.

Using $.ajaxPrefilter like in this example was the best solution for me:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    let error = options.error;
    options.error = function (jqXHR, textStatus, errorThrown) {
        // global error handling first
        console.log('global ajax error');
        
        // override local error handling if exists
        if ($.isFunction(error)) {
            return $.proxy(error, this)(jqXHR, textStatus, errorThrown);
        }
    };
});
ge333
  • 303
  • 1
  • 4
  • 7
0

I think it's a bad idea. I think wrapping $.ajax is fine, but you're talking about re-defining it. Anyone who doesn't realize this will get unexpected results.

As others have mentioned, binding a handler to $.ajaxError is the way to go.

Rob Sobers
  • 20,737
  • 24
  • 82
  • 111