0

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?

Community
  • 1
  • 1
jitender
  • 10,238
  • 1
  • 18
  • 44
  • 1
    Post here a code of `$scope.student.update()` function. – Knut Holm Jul 13 '16 at 13:02
  • why are you calling a general `$scope.student.update();` without usign the `item`? – Rhumborl Jul 13 '16 at 13:03
  • this is an generic call to api service also i can use callback after updating this student if it help in my problem.As follow $scope.student.update(function(){callback here}) – jitender Jul 13 '16 at 13:04
  • @Rhumborl No i need item to set student properties i have removed the code to keep my question simple – jitender Jul 13 '16 at 13:06

4 Answers4

1

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");
});
Knut Holm
  • 3,988
  • 4
  • 32
  • 54
  • @jitender it really depends how a function `$scope.student.update();` looks like - it has to return promise... I also don't understand why doesn't this function take any parameter? – Knut Holm Jul 13 '16 at 13:09
  • @Akarienta This is an generic service something very big to explain – jitender Jul 13 '16 at 13:11
  • @jitender the important thing is what does this function return – Knut Holm Jul 13 '16 at 13:12
  • This function will return student model after update – jitender Jul 13 '16 at 13:13
  • @jitender and is it promise? I think the problem is in `$scope.student.update();` function; not in the code you have posted – Knut Holm Jul 13 '16 at 13:15
  • There is no promise inside that service .how i can return because its work for others too like $scope.course.update etc – jitender Jul 13 '16 at 13:22
  • @jitender this is the reason why we need to see code of `$scope.student.update();` function – Knut Holm Jul 13 '16 at 13:23
  • self.update = function(item, callback) { that.post(item, self.getUrl("update") , function(err, data) { if (self.formatter) { data = self.formatter(data); } callback(err, data); }); }; – jitender Jul 13 '16 at 13:26
  • @jitender place `return` keyword before `that.post` and then try my code again – Knut Holm Jul 13 '16 at 13:29
  • @jitender yeah, just go deeper - every function in the chain has to return a promise, just check a `that.post()` now and make it to return a promise (`$http.post()` returns a promise) – Knut Holm Jul 13 '16 at 13:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/117221/discussion-between-akarienta-and-jitender). – Knut Holm Jul 13 '16 at 13:36
  • @Akarienta Thanks its start working for me as i go deeper and use to return from every function in the chain – jitender Jul 14 '16 at 07:50
  • @jitender no problem glad I could help – Knut Holm Jul 19 '16 at 14:54
1

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>
Srijith
  • 1,434
  • 9
  • 14
1
$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( ... );
}
DerekMT12
  • 1,329
  • 11
  • 15
0

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.

Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50