Search code examples
javascriptangularjspromiseangularjs-service

AngularJS | Create chained promise


I would like to create a chained promise for my service provider:

this.$get = function($q, $window, $rootScope) {
    var $facebook=$q.defer();

    $rootScope.$on("fb.load", function(e, FB) {
        $facebook.resolve(FB);
    });

    $facebook.api = function () {
        var args=arguments;
        args[args.length++] = function(response) {
            $facebook.resolve(response);
        };

        $facebook.promise.then(function(FB) {
            FB.api.apply(FB, args);
        });

        return $facebook.promise;
    };

    return $facebook;
};

Than I call to the promise: $scope.user=$facebook.api("/me");

The problem is that because the deferred was already resolved its not wait until the api method will resolve it..

How can I chain them in a way the last promise will wait until the last promise will resolved?


Solution

  • It seems like you need two separate promise objects: One for the fb.load event and another one for the result of the API call.

    Try chaning your code to read -

    this.$get = function($q, $window, $rootScope) {
        var apiLoaded=$q.defer();
    
        $rootScope.$on("fb.load", function(e, FB) {
            apiLoaded.resolve(FB);
        });
        // You should reject the promise if facebook load fails.
    
        $facebook.api = function () {
            var resultDefer = $q.defer(),
                args=arguments;
    
            args[args.length++] = function(response) {
                $rootScope.$apply(function() {
                    resultDefer.resolve(response);
                    // you should reject if the response is an error
                });
            };
    
            return apiLoaded.promise.then(function(FB) {
                FB.api.apply(FB, args);
                return resultDefer.promise;
            });
        };
    
        return $facebook;
    };
    

    Also note that whenever you call resolve() from non-angularish code, you will need to wrap it with $rootScope.$apply(), otherwise then promise 'then' handlers will not get executed. Good luck!