25

Fyi, I'm just starting to learn jQuery promises, so I may be a bit confused here.

Anyway, I have an AJAX request that I want to reject from within a done filter based on the content of the response:

return doAJAXRequest().then(function (data) {
    if (data.responseText == "YES") {
        return doOtherAJAXRequest();
    } else {
        this.reject(data);
    }
});

That didn't work as I expected:

Uncaught TypeError: Object #<Object> has no method 'reject'

How do I make this promise fail based on its response? Is that possible? Or am I just confused about what needs to be done here?

Ajedi32
  • 45,670
  • 22
  • 127
  • 172
  • Try changing this.reject to $(this).reject. – rtimoshenko Jul 23 '13 at 01:39
  • @rtimoshenko Are you sure that's right? – alex Jul 23 '13 at 01:42
  • @rtimoshenko That doesn't seem to be working, I'm still getting the same error. Edit: Actually it's not exactly the same, but still very similar. (`Uncaught TypeError: Object [object Object] has no method 'reject'`) – Ajedi32 Jul 23 '13 at 01:42
  • 1
    My mistake, I saw "this" and made an assumption. Have you compared your code with the documentation? http://api.jquery.com/deferred.then/ You might try using the global $.Deferred().reject. Here's a jsFiddle: http://jsfiddle.net/pgBCD/ – rtimoshenko Jul 23 '13 at 01:54
  • 1
    @rtimoshenko Well, this seems to work: http://jsfiddle.net/pgBCD/1/ – Ajedi32 Jul 23 '13 at 02:10
  • possible duplicate of [Throwing an Error in jQuery's Deferred object](http://stackoverflow.com/questions/10843297/throwing-an-error-in-jquerys-deferred-object) – Bergi Jan 21 '14 at 15:15

1 Answers1

36

In jQuery (unlike some other libs), transmogrifying a promise from a 'resolved' state to an 'rejected' state is slightly verbose, requiring the explicit creation and rejection of a new Deferred.

function foo() {
    return doAJAXRequest().then(function (data, textStatus, jqXHR) {
        if (data.responseText == "YES") {
            return doOtherAJAXRequest(data);
        } else {
            return $.Deferred().reject(jqXHR, data, 'Not YES').promise();
        }
    });
)

Here, the promise returned if data.responseText !== "YES" mimics (in part) a failed ajax request, while still allowing data to be passed. This is (probably) important for the downstream .fail() handler, which must handle both genuine ajax failures AND transmogrified success conditions, without knowing which one occurred until it reads errorThrown.

foo().fail(function(jqXHR, textStatus, errorThrown) {
    if(errorThrown == 'Not YES') {
        //transmogrified success
        var data = textStatus;
        ...
    }
    else {
        //genuine ajax failure
        ...
    }
}); 

It is generally easier to pass data in this way rather than re-obtaining it from the jqXHR object. This is particularly true with JSON encoded data, which would otherwise need to be decoded a second time in the fail handler.

Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • 3
    I don't think the promise() part is needed (or not anymore), which makes the call a bit less ugly/longish. – mikus Jun 20 '16 at 10:35