1

I'm trying to wrap my head around promises in angular and i have the example below that I'd like to convert to use promises so hopefully it will help me go "Ah ha!".

All the examples that I find on the interwebs are using services/factories/etc and I just want to know the best way to make something simple like this use promises.

angular.module('web').controller('CardsCtrl',function($scope, $http, $q){

    // Don't worry about how the variable "users" gets populated, let's just say it came into magical existance from a unicorn's horn.
    $scope.users = users;

    // Loop through all the users
    for(var i = 0; i < $scope.users .length; i++) {

      // THIS FAILS BECAUSE THE LOOP FINISHES BEFORE THE 1ST GET REQUEST FINISHES SO WE CAN'T REFERENCE THE I VARIABLE
      $http.get('http://uifaces.com/api/v1/random', function(face) {
        $scope.users[i].face = face.image_urls.mini;
      });
    }
});
Catfish
  • 18,876
  • 54
  • 209
  • 353
  • are you using a resfull api? if so $resource service is designed for that – bto.rdz May 20 '14 at 19:07
  • No i'm just using one endpoint. http://uifaces.com/api – Catfish May 20 '14 at 19:08
  • well i am not sure of this, becasue I normally use $resource service but you should try it. what I usually do is `$resource('myurl').$promise()` that will convert your requesto to promisse, then you can use `.then()` if you need it – bto.rdz May 20 '14 at 19:10
  • this is usefull https://egghead.io/lessons/angularjs-chained-promises – bto.rdz May 20 '14 at 19:11

2 Answers2

4

What you have is not an issue with promises. It's just the classical "closure in a loop" issue.

Fix it like this:

for(var i = 0; i < $scope.users .length; i++) {
  (function(i) {
    $http.get('http://uifaces.com/api/v1/random', function(face) {
      $scope.users[i].face = face.image_urls.mini;
    });
  }(i));
}
Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • Well i'd like to learn promises so i'm curious how you would convert this to use promises. But i am also interested in having you elaborate on this function inside the loop that you have. – Catfish May 20 '14 at 19:16
  • @Catfish w.r.t the closure issue, just go there: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – Florian Margaine May 20 '14 at 19:21
  • @Catfish for the promises issue, you should first have an easier example: have some callback hell to transform to promises. Well simpler. Sequences are not hard with promises, but they're definitely harder than the simple stuff you should go through first. – Florian Margaine May 20 '14 at 19:21
3

Here is how I'd write it:

 $q.all($scope.users.map(function(user){
      return $http.get('http://uifaces.com/api/v1/random').then(function(face){
           return user.face = face.image_urls.mini;
      });
 })).then(function(results) {
    // results contains the images actually used, so you can use it here too
 });
Esailija
  • 138,174
  • 23
  • 272
  • 326
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504