Florent Valdelievre Florent Valdelievre - 3 months ago 11
Javascript Question

Chain promises with AngularJS

I have a service called paymentStrategy that get injected in my controller.

$scope.buy = function() {
paymentStrategy.buy()
.then(function(response) {

}
}


This buy method from paymentStrategy triggers several methods that needs to be called sequentially. When all the methods within buy() are done, then() needs to be called.

It is probably trivial but I am quite new to angular.

At the moment, buy().then() gets triggered straight after the init() methods.
I have the feeling we need to put all theses methods in a array of promises and apply $q.all().

Any help or suggestion would be greatly appreciated

angular.module('deps-app.payment.services', []).
factory('paymentStrategy', function($q) {

var deferred = $q.defer();
var ITEM_TO_PURCHASE = "test.beer.managed";
var promises = [];

var handlerSuccess = function(result) {
deferred.resolve(result);
};

var handlerError = function(result) {
deferred.reject(result);
};

_init = function() {

inappbilling.init(handlerSuccess, handlerError, { showLog:true });
return deferred.promise;
}

_purchase = function() {
inappbilling.buy(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
return deferred.promise;
}

_consume = function() {
inappbilling.consumePurchase(handlerSuccess, handlerError, ITEM_TO_PURCHASE);
return deferred.promise;
}

return {

buy: function() {

_init();
.then(_purchase());
.then(_consume());

return deferred.promise;
}

}
});

Answer

Make all methods atomar, by adding their own promises. In your code, the first resolve will complete the whole request.

If the methods have their own promise, you can chain them with ease.

angular.module('deps-app.payment.services', [])
  .factory('paymentStrategy', function($q) {

    var ITEM_TO_PURCHASE = "test.beer.managed";

    _init = function() {
      return $q(function (resolve, reject) {
        inappbilling.init(resolve, reject, { showLog: true }); 
      });
    };

    _purchase = function() {
      return $q(function (resolve, reject) {
        inappbilling.buy(resolve, reject, ITEM_TO_PURCHASE); 
      });
    };

    _consume = function() {
      return $q(function (resolve, reject) {
        inappbilling.consumePurchase(resolve, reject, ITEM_TO_PURCHASE);
      });
    };

    return  {
      // In this case, you don't need to define a additional promise, 
      // because placing a return in front of the _init, will already return 
      // the promise of _consume.
      buy: function() {    
        return _init()
          .then(_purchase)  
          // remove () from inside the callback, to pass the actual method 
          // instead the result of the invoked method.
          .then(_consume);      
      }    
    };
  });
Comments