Asynchronous array update in Angular

I have an idea where I make tweets. Inside the tweets there is an array of user_mentions. From this array I want to get one user, make another API request, get an avatar for the user, and then render it. The view looks like this:

<md-item ng-repeat="item in content">
  <div class="md-tile-left" ng-if="item.show">
     <img ng-src="{{item.thumb}}" class="face" alt="{{item.name}}">
  </div>
  <div class="md-tile-content">
     {{item.text}}
  </div>
</md-item>

Content will contain all tweets. Initially, the content [i] .show is false for all i. The controller code looks like this:

for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     UserAvatar.get(data[i].user_mentions[0].screen_name).then(function(data){
        $scope.content[i].thumb = data.avatar;
        $scope.content[i].show = true;
     });
  }
}

Now the problem is that after calling the UserAvatar service, the variable I will continue to increase. Thus, by the time the callback is reached, I will have the value data.length (therefore, the undefined error will be selected). I found a workaround by passing the API to me and then returning it:

    UserAvatar.get(data[i].user_mentions[0].screen_name, i).then(function(data){
        $scope.content[i].thumb = data.avatar;
        $scope.content[i].show = true;
    });

I understand that this is just a hack to make it work, but is there a smarter way to do this?

+4
3

, , , ( $scope, vars, i), , , , " , , i .then i, ? :

1)

function getAvatar(name, contentToUpdate) {
  return UserAvatar.get(name)
      .then(function (data) {
        contentToUpdate.thumb = data.avatar;
        contentToUpdate.show = true;
      });
}

for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     getAvatar(data[i].user_mentions[0].screen_name, $scope.content[i]);
  }
}

.then, i

2)

for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     UserAvatar.get(data[i].user_mentions[0].screen_name).then((function(content) {
        return function (data) {
          content.thumb = data.avatar;
          content.show = true;
        }
     })($scope.content[i]));
  }
}

IIFE , , IIFE , , ( onFulfilled .then), no i

: , , :

,

, , , Nicholas Zakas JavaScript -, :)

+3

, for, , . - . forEach()/map() IIFE ((function(i) { ... })(i);).

:

  var promises = data.map(function(item, index) {
     if (item.user_mentions[0]) {
        return UserAvatar.get(item.user_mentions[0].screen_name)
           .then(function(itemData) {
             $scope.content[index].thumb = itemData.avatar;
             $scope.content[index].show = true;
           });
     } else {
        return $q();
     }
  });
  $q.all(promises).then(function() {
     // All complete
  });
+1

, , , ?

@MukeshAgarwal , , UserAvatar.get - .

, i .

, , , :

:

for (var i = 0; i < 10; i++) {

    // do something async
    setTimeout(function() { 
        console.log(i); // <- This will log 10 each time (the value of i at execution)
    }, 1000)

}

:

for (var i = 0; i < 10; i++) {

    (function() {      
        var j = i;   // <- The value of i is captured in j. j is in a closure
        // do something async
        setTimeout(function() { 
            console.log(j);  // <- This will log 0, then 1, then 2 ... then 9 
        }, 1000)
    })()

}
+1

All Articles