Reputation: 10429
I am sending multiple HTTP calls to update items inside foreach loop and need a callback after all request complete. I found this but didn't help.
My code:
$q.all(_($scope.students.items).each(function(item) {
$scope.student.update(); //this is an http call
})).then(function() {
// I need a callback need here
alert("complete"); //should be shown after all students get updated but it is
// called before all network calls got complete
});
Here is generic update function
self.update = function(item, callback) {
that.post(item, self.getUrl("update") , function(err, data) {
if (self.formatter) {
data = self.formatter(data);
}
callback(err, data);
});
};
Any suggestions?
Upvotes: 0
Views: 995
Reputation: 1444
You could try this as well by using map
$q.all(_($scope.students.items).map(function(item) {
item.update();
})).then(function() {
alert("complete");
});
I have updated the code here with the below snippet. I have used some methods that return simple promises. Includes two ways you could do this.
angular.module('demoApp', []).controller('DemoController', function($scope, $q, $timeout) {
var a = function() {
var deferred = $q.defer();
console.log('Executing a');
deferred.resolve();
return deferred.promise;
};
var b = function() {
var deferred = $q.defer();
console.log('Executing b');
deferred.resolve();
return deferred.promise;
};
var c = function() {
var deferred = $q.defer();
console.log('Executing c');
deferred.resolve();
return deferred.promise;
};
var f = [{
call: a
}, {
call: b
}, {
call: c
}];
$scope.mapTest = function() {
$q.all(f.map(function(item) {
return item.call();
})).then(function() {
console.log("complete");
});
};
$scope.promisePush = function() {
var promises = [];
angular.forEach(f, function(item) {
promises.push(item.call());
});
$q.all(promises).then(function() {
console.log('complete');
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="demoApp">
<div ng-controller="DemoController">
<button ng-click="mapTest()">Q.all using map</button>
<button ng-click="promisePush()">Q.all using promise push</button>
</div>
</body>
Upvotes: 1
Reputation: 4162
You miss a return
keyword in update()
function because it has to return a promise (and, of course, that.post()
function has to return a promise too):
self.update = function(item, callback) {
return that.post(item, self.getUrl("update") , function(err, data) {
if (self.formatter) {
data = self.formatter(data);
}
callback(err, data);
});
};
Then this should work:
var promises = [];
_($scope.students.items).each(function(item) {
promises.push($scope.student.update());
})
$q.all(promises).then(function() {
alert("complete");
});
Upvotes: 1
Reputation: 20162
You should not send the same ajax in foreach. This should be single ajax and update should be done in callback, so send one ajax like "studentsUpdate" and in response do foreach on studenst collection and update objects data. Good practice is less ajax calls.
Upvotes: 0
Reputation: 1349
$q.all(_.map($scope.students.items, function(item) {
return item.update();
})).then(function() {
//everything has completed
});
The update function on each item in $scope.student.items
will have to return the promise for this to work. Something like:
function update() {
return $http( ... );
}
Upvotes: 1