Benno
Benno

Reputation: 3008

jQuery Deferred - returning promises up a call chain

RESOLVED

I'm having an issue with $.Deferred in jQuery 1.7.1. I think the behaviour of the returning values from when/then/fail etc is different to what I think it should be.

This is what I'm trying to do:

  1. Call $.when(setInstall(true)).then('do something'); (this works, it waits for the ajax request)
  2. --> Call this.inInstallableRegion() which runs an ajax request.
  3. ---> When the AJAX request is successful, I want to resolve or reject inInstallableRegion's $df depending on the result of the AJAX request.
  4. ----> this.inInstallableRegion has detected there is an error, so it rejects $df's promise (this works) and I want it to return that to setInstall. I'm assuming that the return value of this.inInstallableRegion's $.done() is returned as the result of this.inInstallableRegion (i.e. rejected in this case).

For some reason it rejects $df, but when I go to setInstall, it runs the $.done function, instead of the $.fail one :.. am I missing something?

Sorry, can't really do a jsfiddle for this :\ can't think of a way to simplify it down more... my brain is totally fried :|

These are the two functions:

    this.setInstall = function (status) {
        $df1 = new $.Deferred();
        if (status === true) {
            var self = this;
            return $.when(this.inInstallableRegion()).done(function (json) {
                self.setInstallDetail(json);
                self.setDispatchCompany();
                $df1.resolve();
                return $df1.promise();
            }).fail(function (json) { 
                self.notifyNoInstall(json.error); 
                self.setInstall(false);
                self.setDispatchCompany();
                $df1.reject();
                return $df1.promise();
            });
        } else {
            this.setInstallDetail({
                install: 0,
                ref_id: 0,
                retail_price: 0
            });
        }
        this.setDispatchCompany();
        $df1.resolve();
        return $df1.promise();
    };

////////////////////////////////////////

this.inInstallableRegion = function () {

    $df = new $.Deferred();

    var params = {
        dataType: 'json',
        data: $.param({
            'zip': this.order.delivery.zip
        }),
        action: 'getinstaller',
        cache: true
    };

    return $.when(this.sendData(params, 'installerCache', true)).done(function (json) {
        if (json.error) {
            $df.reject();
            return $df.promise();
        } else {
            $df.resolve();
            return $df.promise();
        }
    });

};

Upvotes: 2

Views: 2836

Answers (1)

Benno
Benno

Reputation: 3008

I figured it out.

In order for setInstall to wait for inInstallableRegion to finish, inIntsallableRegion had to return something. It wouldn't work to just return the ajax request, because it'd return just when that was completed or not. It wouldn't return whether or not I wanted to accept or reject based on the result of the ajax request.

So I just made it return its own deferred object of when the ajax ran AND when the result was processed. I did this in inInstallableRegion

var self = this;
return $.Deferred(function(dfd) {
  self.sendData(params, 'installerCache', true).then(function(json) {
    if(json.error) {
      dfd.reject();
    } else {
      dfd.resolve();
    }
    return dfd.promise();
  });
});

Upvotes: 4

Related Questions