Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs $q.all

I have implemented the $q.all in angularjs, but I can not make the code work. Here is my code :

UploadService.uploadQuestion = function(questions){          var promises = [];          for(var i = 0 ; i < questions.length ; i++){              var deffered  = $q.defer();             var question  = questions[i];               $http({                  url   : 'upload/question',                 method: 'POST',                 data  : question             }).             success(function(data){                 deffered.resolve(data);             }).             error(function(error){                 deffered.reject();             });              promises.push(deffered.promise);         }          return $q.all(promises);     } 

And here is my controller which call the services:

uploadService.uploadQuestion(questions).then(function(datas){     //the datas can not be retrieved although the server has responded     },  function(errors){     //errors can not be retrieved also  }) 

I think there is some problem setting up $q.all in my service.

like image 875
themyth92 Avatar asked Jan 23 '14 14:01

themyth92


People also ask

What is Q in angular?

$q is integrated with the $rootScope. Scope Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI. Q has many more features than $q, but that comes at a cost of bytes.

What is Q defer () in AngularJS?

Simply put you can use $q. defer() to create a Promise. A Promise is a function that returns a single value or error in the future. So whenever you have some asynchronous process that should return a value or an error, you can use $q. defer() to create a new Promise.

What is promises in AngularJS?

Promises in AngularJS are provided by the built-in $q service. They provide a way to execute asynchronous functions in series by registering them with a promise object. {info} Promises have made their way into native JavaScript as part of the ES6 specification.

What is $HTTP in AngularJS?

$http is an AngularJS service for reading data from remote servers.


2 Answers

In javascript there are no block-level scopes only function-level scopes:

Read this article about javaScript Scoping and Hoisting.

See how I debugged your code:

var deferred = $q.defer(); deferred.count = i;  console.log(deferred.count); // 0,1,2,3,4,5 --< all deferred objects  // some code  .success(function(data){    console.log(deferred.count); // 5,5,5,5,5,5 --< only the last deferred object    deferred.resolve(data); }) 
  • When you write var deferred= $q.defer(); inside a for loop it's hoisted to the top of the function, it means that javascript declares this variable on the function scope outside of the for loop.
  • With each loop, the last deferred is overriding the previous one, there is no block-level scope to save a reference to that object.
  • When asynchronous callbacks (success / error) are invoked, they reference only the last deferred object and only it gets resolved, so $q.all is never resolved because it still waits for other deferred objects.
  • What you need is to create an anonymous function for each item you iterate.
  • Since functions do have scopes, the reference to the deferred objects are preserved in a closure scope even after functions are executed.
  • As #dfsq commented: There is no need to manually construct a new deferred object since $http itself returns a promise.

Solution with angular.forEach:

Here is a demo plunker: http://plnkr.co/edit/NGMp4ycmaCqVOmgohN53?p=preview

UploadService.uploadQuestion = function(questions){      var promises = [];      angular.forEach(questions , function(question) {          var promise = $http({             url   : 'upload/question',             method: 'POST',             data  : question         });          promises.push(promise);      });      return $q.all(promises); } 

My favorite way is to use Array#map:

Here is a demo plunker: http://plnkr.co/edit/KYeTWUyxJR4mlU77svw9?p=preview

UploadService.uploadQuestion = function(questions){      var promises = questions.map(function(question) {          return $http({             url   : 'upload/question',             method: 'POST',             data  : question         });      });      return $q.all(promises); } 
like image 70
Ilan Frumer Avatar answered Oct 08 '22 22:10

Ilan Frumer


$http is a promise too, you can make it simpler:

return $q.all(tasks.map(function(d){         return $http.post('upload/tasks',d).then(someProcessCallback, onErrorCallback);     })); 
like image 33
Zerkotin Avatar answered Oct 08 '22 23:10

Zerkotin