Working on a sandbox app to learn angular.js I have encountered the following pattern in several places in my code. I find myself having to query the mongoDB in a loop. As I understand it, each call happens in its own async task. How do I know when all the tasks are completed?
For instance, I have an array of states. Often I need to set someProperty to someNewValue for each of the states. Once all the states have been updated I would like to call someFunction().
for (var i = 0; i < $scope.states.length; i++) {
$scope.states[i].someProperty = someNewValue;
$scope.states[i].$update({stateId: $scope.states[i].id}, function() {
someFunction();
});
}
For now, the only way I can think of doing this is to call someFunction() every time each update succeeds. I know there must be a smarter and better way of doing this.
What would you be your approach?
Working on a sandbox app to learn angular.js I have encountered the following pattern in several places in my code. I find myself having to query the mongoDB in a loop. As I understand it, each call happens in its own async task. How do I know when all the tasks are completed?
For instance, I have an array of states. Often I need to set someProperty to someNewValue for each of the states. Once all the states have been updated I would like to call someFunction().
for (var i = 0; i < $scope.states.length; i++) {
$scope.states[i].someProperty = someNewValue;
$scope.states[i].$update({stateId: $scope.states[i].id}, function() {
someFunction();
});
}
For now, the only way I can think of doing this is to call someFunction() every time each update succeeds. I know there must be a smarter and better way of doing this.
What would you be your approach?
Share Improve this question asked Dec 3, 2013 at 9:26 Francesco GallarottiFrancesco Gallarotti 1,2271 gold badge16 silver badges40 bronze badges 1- 1 I answered a similar question earlier stackoverflow.com/questions/20144132/… – Chandermani Commented Dec 3, 2013 at 10:29
1 Answer
Reset to default 20Promises and $q.all
(ref) are your friends.
In more detail, you will have to make a promise for each call (if the call itself does not return one), push them in an array and call $q.all(promises).then(allFinished)
. Naive case, where $update()
does not return a promise:
function callUpdate(x, promises) {
var d = $q.defer();
x.$update({stateId: $scope.states[i].id}, function() {
someFunction();
d.resolve(); // it may be appropriate to call resolve() before someFunction() depending on your case
});
promises.push(d.promise);
}
...
var promises = [];
for (var i = 0; i < $scope.states.length; i++) {
$scope.states[i].someProperty = someNewValue;
callUpdate($scope.states[i], promises);
}
$q.all(promises).then(function() {
// called when all promises have been resolved successully
});
The reason for the existence of callUpdate()
is to encapsulate the deferred object handling and return the promise.