简体   繁体   中英

Angular js call back after multiple http calls complete with foreach

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?

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");
});

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.

  • Pushing promises into an array and using q.all
  • Using map with q.all

 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> 

$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( ... );
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM