Vicheanak
Vicheanak

Reputation: 6684

How to Wait for Multiple ngResource $resource Queries to Resolve

I have these ngResource queries in my controller:

Ages.query(function(ages){
    $scope.ages = ages;
});

Skinissues.query(function(skinissues){
    $scope.skinissues = skinissues;
});

Skintypes.query(function(skintypes){
    $scope.skintypes = skintypes;
});

Activities.query(function(activities){
    $scope.activities = activities; 
});

In the same controller in findOne function:

$scope.findOne = function() {

    Products.get({
        productId: $routeParams.productId
    }, function(product) {
        for (var i = 0; i < product.ages.length; i ++){
            for (var j = 0; j < $scope.ages.length; j ++){
                if (product.ages[i].id == $scope.ages[j].id){
                    $scope.ages[j]['ticked'] = true;
                }
            }
        }
        for (var i = 0; i < product.activities.length; i ++){
            for (var j = 0; j < $scope.activities.length; j ++){
                if (product.activities[i].id == $scope.activities[j].id){
                    $scope.activities[i]['ticked'] = true;
                }
            }
        }
        for (var i = 0; i < product.skintypes.length; i ++){
            for (var j = 0; j < $scope.skintypes.length; j ++){
                if (product.skintypes[i].id == $scope.skintypes[j].id){
                    $scope.skintypes[i]['ticked'] = true;
                }
            }
        }
        for (var i = 0; i < product.skinissues.length; i ++){
            for (var j = 0; j < $scope.skinissues.length; j ++){
                if (product.skinissues[i].id == $scope.skinissues[j].id){
                    $scope.skinissues[i]['ticked'] = true;
                }
            }
        }
        for (var i = 0; i < $scope.parents.length; i ++){
            if ($scope.parents[i].id == product.parent.id){
                $scope.parents[i]['ticked'] = true;
            }
        }
        console.log('Products', product);
        $scope.product = product;
    });

};

This code, sometimes, it works, sometimes it doesn't, because in the findOne function, sometimes, the $scope.ages $scope.skinissues $scope.skintypes or $scope.activities is undefined.

This happens because their queries haven't finished yet.

What can I do to solve this problem?

Please help. Thanks.

Upvotes: 1

Views: 883

Answers (2)

georgeawg
georgeawg

Reputation: 48968

Use $q.all to resolve the $resource promises.

angular.module('mean.variables')
.factory('Variables', function($q, Products, Ages, Activities, Skinissues, Skintypes, _){

    return {
        get: function(){
            var promiseHash = {};

            promiseHash.ages = Ages.query().$promise;
            promiseHash.skinissues = Skinissues.query().$promise;
            promiseHash.skintypes = Skintypes.query().$promise;
            promiseHash.activities = Activities.query().$promise;
            promiseHash.parents = Products.query().$promise;

            return $q.all(promiseHash);

        }
    }
});

The above example function returns a promise that either resolves sucessfully to a hash of the query objects or resolves rejected with the first rejected response object.

The advantage of using $q.all() instead of $q.defer is that the promise chains aren't broken and error responses are retained for clients of the factory.

From the Docs:

The Resource instances and collections have these additional properties:

  • $promise: the promise of the original server interaction that created this instance or collection.

On success, the promise is resolved with the same resource instance or collection object, updated with data from server. This makes it easy to use in resolve section of $routeProvider.when() to defer view rendering until the resource(s) are loaded.

On failure, the promise is rejected with the http response object, without the resource property.

If an interceptor object was provided, the promise will instead be resolved with the value returned by the interceptor.

--AngularJS ngResource API Reference


all(promises);

Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.

Parameters

An array or hash of promises.

Returns

Returns a single promise that will be resolved with an array/hash of values, each value corresponding to the promise at the same index/key in the promises array/hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value.

--AngularJS $q Service API Reference -- $q.all

Upvotes: 2

Vicheanak
Vicheanak

Reputation: 6684

Thanks guy, I've came up with this service by using setInterval to check if all variable are defined.

angular.module('mean.variables')
.factory('Variables', ['$q', 'Products', 'Ages', 'Activities', 'Skinissues', 'Skintypes', '_', function($q, Products, Ages, Activities, Skinissues, Skintypes, _){

    return {
        get: function(){
            var variables = {};
            var defer = $q.defer();
            Ages.query(function(res){
                variables.ages = res;
            });

            Skinissues.query(function(res){
                variables.skinissues = res;
            });

            Skintypes.query(function(res){
                variables.skintypes = res;
            });

            Activities.query(function(res){
                variables.activities = res; 
            });

            Products.query(function(res){
                variables.parents = res;
            });

            var timer = setInterval(function(){
                if (variables.ages && variables.activities && variables.skinissues && variables.skintypes && variables.parents){
                    defer.resolve(variables);
                    clearInterval(timer);
                }
            }, 50);

            return defer.promise;

        }
    }

}])

Upvotes: 0

Related Questions