47

By using jquery ajax function, I can do something like:

$.ajax({

  url: url,
  type: 'GET',
  async: true,
  dataType: 'json',
  data: data,

 success: function(data) {

     //Handle server response here

  },

 error: function(xhr, status, error){

    //Handle failure here

 }

});

I got two questions to ask based on above code:

  1. When will the jquery.ajax() error callback be called??

  2. What if server response to me a json object with string message "There is an error". Which means the request is still send successfully, but I got server response {message: "There is an error"}.

I think no matter what string value server is responsed, if client got server's response, the jquery.ajax() success callback will be triggered anyway.

I'd like to ask if server specifically returns to me a JSON object with string value like {message: 'There is an error'}, could server do something so that this response could be handled in jquery.ajax() error callback instead of success callback?

Liam
  • 27,717
  • 28
  • 128
  • 190
Leem
  • 17,220
  • 36
  • 109
  • 159

6 Answers6

39

The error callback will be executed when the response from the server is not going to be what you were expecting. So for example in this situations it:

  • HTTP 404/500 or any other HTTP error message has been received
  • data of incorrect type was received (i.e. you have expected JSON, you have received something else).

In your situation the data is correct (it's a JSON message). If you want to manually trigger the error callback based on the value of the received data you can do so quite simple. Just change the anonymous callback for error to named function.

function handleError(xhr, status, error){

    //Handle failure here

 }

$.ajax({

  url: url,
  type: 'GET',
  async: true,
  dataType: 'json',
  data: data,

 success: function(data) {
     if (whatever) {
         handleError(xhr, status, ''); // manually trigger callback
     }
     //Handle server response here

  },

 error: handleError
});
RaYell
  • 69,610
  • 20
  • 126
  • 152
  • 4
    Why define handleError in a whole separate location? Why not just define it inline like this: `error: handleError = function(xhr, status){//handle server response here}` – dallin Apr 29 '14 at 00:07
  • 2
    @dallin because it allows you to not duplicate code. The server might respond with code 200 which triggers the "success" callback. Or, a bad code like 400, 404, or 500 would trigger the "error" callback. In both cases you probably want to handle the error in a centralized way. – Michael Butler May 31 '15 at 22:29
  • 1
    @MichaelButler I think you might misunderstand what I was suggesting. I believe you can define a function called handleError directly in the error property ( error: handleError = function(xhr, status) ). This allows you to still manually call the function and handle the error in a centralized location. It would keep the error handling directly in the ajax call, centralizing things further. Here's a jsfiddle with a simplified example: http://jsfiddle.net/dhq01bLv/ – dallin Jun 26 '15 at 00:04
  • @dallin thanks, didn't know you can do that. your solution would give the best of both worlds, so to speak. – Michael Butler Jun 26 '15 at 00:52
28

We presume the server is sending JSON, and in case of a successful request we'll get something like this:

{
    success: true,
    data: {
        name: 'Foo'
    }
}

... and on failure:

{
    success: false,
    error: 'Something bad happened.'
}

Then we simply filter the response with a $.Deferred:

$.get('http://localhost/api').then(function(res) {
    var filter = $.Deferred();

    if (res.success) {
        filter.resolve(res.data);
    } else {
        filter.reject(res.error);
    }

    return filter.promise();
}).done(function(data) {
    console.log('Name:',  data.name); // Outputs: Foo
}).fail(function(error) {
    console.log('Error:', error); // Outputs: Something bad happened.
})
kosinix
  • 1,779
  • 1
  • 18
  • 22
Simen Brekken
  • 1,468
  • 1
  • 15
  • 23
3

The error callback is for when the Ajax round-trip could not be completed successfully, not something based on your server logic. It would be your responsibility to check for what you consider to be a successful response inside the success callback. i.e. Add a single IF conditional that checks if the message = "There was an error." and include your error logic there, otherwise do the success logic.

An approach to do what you ask for would be to have the server return a 404 header when there is an error, then it would be handled by the error callback. The problem with this approach is that you'd be hiding if there are actual errors, and you wouldn't be able to pass additional data with it.

Fosco
  • 38,138
  • 7
  • 87
  • 101
  • I see, so there is no way to trigger error callback based on what server responsed, right? – Leem Jun 07 '11 at 13:26
  • @Leem It's just a function... I'm having a hard time figuring out why you want that to happen instead of checking for the error in the response data. I added a hack method though. – Fosco Jun 07 '11 at 13:28
  • I would like to see if there is a possibility to trigger error callback in my case, hope this motivation wont give you more hard time. RaYell's answer makes me clear. Thank you also. – Leem Jun 07 '11 at 13:37
2

Simplest thing to do would be to restructure like so:

function handleAjaxError function(xhr, status, error) {
    //Handle failure here
}

$.ajax({
  url: url,
  type: 'GET',
  async: true,
  dataType: 'json',
  data: data,

  success: function(data) {

     //Handle server response here
    if (data.message == 'There is an error')
    {
        handleAjaxError();
        return;
    }

    //... all is good....

  },
  error: handleAjaxError
});
Gary Green
  • 22,045
  • 6
  • 49
  • 75
1

One easy way to do this is to just use the jQuery always() function for your callback and then if you want to manually create an error just take advantage of Duck Typing!

For example:

$.get(url, {"data": data}).always(function(result)
{
    if (typeof result.status !== "undefined" && result.status !== 200) // Status code 200 represents Success/OK
    {
        //handle error
        error = "Your error was " + result.status + " " + result.statusText;
    }
    else
    {
        //success
    }
});

The error section will always be run if there was a natural header error such as a 404 Not Found. If you want to manually return an error, you can just emulate the XHR object normally passed with an error (e.g. in PHP):

public function ServerSideAjaxResponse($data)
{
    if (!$data)
    {
        $response["status"] = 1001; //Make up your own error codes! Yippee! Fun!
        $response["statusText"] = "Error! You forgot to send the data!";
        echo json_encode($return);
        return;
    }
}
dallin
  • 8,775
  • 2
  • 36
  • 41
0

This original question was posted years ago, and perhaps there are better ways of handling this now. Here's a suggestion to handle multiple types of errors, including the OP's question.

Input type (error) example #1

function handleError (type){
type = type || "Connection Issue";
 var value = "Error occurred: " + type;
 alert(value);
}

function checkIfError(response){
    if (response == "DB_ERROR") {
        handleError("Server error");
        throw new Error("JS died"); // optional, keep from running additional script
     }
}

var example = {

    success: function (response) {
        checkIfError(response); // check data if error msg
        // do stuff when proper data sent
        alert(response);

    }, error: handleError // connection error, call error msg
};

test1 = example['error']();

Input type (success:error) example #2

function handleError (type){
type = type || "Connection Issue";
 var value = "Error occurred: " + type;
 alert(value);
}

function checkIfError(response){
    if (response == "DB_ERROR") {
        handleError("Server error");
        throw new Error("JS died"); // optional, keep from running additional script
     }
}

var example = {

    success: function (response) {
        checkIfError(response); // check data if error msg
        // do stuff when proper data sent
        alert(response);

    }, error: handleError // connection error, call error msg
};


test2 = example['success']("DB_ERROR");

Input type (success) example #3

function handleError (type){
type = type || "Connection Issue";
 var value = "Error occurred: " + type;
 alert(value);
}

function checkIfError(response){
    if (response == "DB_ERROR") {
        handleError("Server error");
        throw new Error("JS died"); // optional, keep from running additional script
     }
}

var example = {

    success: function (response) {
        checkIfError(response); // check data if error msg
        // do stuff when proper data sent
        alert(response);

    }, error: handleError // connection error, call error msg
};


test3 = example['success']("Proper Response");

By using functions, if you have multiple calls in your scripts, you can simplify changes.

Have your PHP (or whatever server side code) return the response of "DB_ERROR" (or whatever you want) to trigger the error; allows you to do different things depending on the error.

Ben in CA
  • 688
  • 8
  • 22