Reputation: 632
Am looping over an array and making async calls to an api the returned data need to me merged with a different array the problem am facing when the merge occurs some of the promises have not being resolved yet so the resulting array after the merge is missing data . any ideas how to go about this . (am new to Angular). the array am looping through has at least 200 elements (I don't know the size of the array in advance) i get the id from each element and i call this service:
for (i = 0; i < list.length; i++) {
service.getRawHtml(list[i].service_object_id)
.then(function(res){
temp=htmlToArray(res);
htmlDataList.push(temp);
}, function(err){
// error
})
}
service.getRawHtml=function (id){
var defer = $q.defer();
$http({
method: 'GET',
url: 'http://wlhost:50000/'+id
}).success(function (response) {
defer.resolve(response);
}).error(function (data, status) {
console.log("Failure");
defer.reject(err);
});
return defer.promise;
}
Thanks in advance.
Upvotes: 0
Views: 2375
Reputation: 10712
just to clerify @nodes solution:
var promisesToWaitFor = [];
for (i = 0; i < list.length; i++) {
var promis = service.getRawHtml(list[i].service_object_id)
promisesToWaitFor.push(promis)
}
$q.all(promisesToWaitFor).then(function(resultsArray) {
var flatten = [].concat.apply([],resultsArray);
temp=htmlToArray(flatten);
htmlDataList.push(temp);
}, function(err) {
// error
});
Upvotes: 2
Reputation: 8879
As @ndoes suggests, this can be done with $q.all()
, which takes an array of promises and resolves when all of them are resolved, or rejects if any of them is rejected.
You're calling the asynchronous function inside the for loop which will execute, but as soon as all of the function calls have been made, the code will continue synchronously. There wont be any magical awaiting for all the promises to resolve.
What you instead should do is to push all of the returning promises to an array, then use $q.all()
to await them all.
//Declare an array to which we push the promises
var promises = [];
for (i = 0; i < list.length; i++) {
//Call the service and push the returned promise to the array
promises.push(service.getRawHtml(list[i].service_object_id));
}
//Await all promises
$q.all(promises)
.then(function(arrayOfResults){
//Use your result which will be an array of each response after
//it's been handled by the htmlToArray function
})
.catch(function(err){
//Handle errors
});
I took the opportunity to refactor your code at the same time, as it is implementing the deferred anti-pattern. Since $http
already returns a promise, there's no need to create and return a new one. Simply return it right away like
service.getRawHtml = function (id){
return $http({
method: 'GET',
url: 'http://wlhost:50000/'+id
}).success(function (response) {
return htmlToArray(response);
}).error(function (data, status) {
console.log("Failure");
$q.reject(error);
});
}
Upvotes: 2
Reputation: 678
Use $q.all - From the documentation:
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
Example usage:
$q.all([
getPromise(),
getPromise(),
getPromise()
]).then(function(value) {
$scope.result1 = value[0];
$scope.result2 = value[1];
$scope.result3 = value[2];
}, function(reason) {
$scope.result = reason;
});
Upvotes: 4