Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return object from Function to ng-repeat in AngularJS

I am trying to return an object from a function to ng-repeat:

<ul ng-controller="Users" ng-repeat="user in users">
    <li ng-controller="Albums" ng-repeat="album in getAlbumList(user.name)">
        {{album.title}}
    </li>
</ul>

.controller('Albums', ['$scope','Imgur', function($scope, Imgur) {
    $scope.getAlbumList = function(user) {
        Imgur.albumList.get({user:user},    
            function(value) {
                return value.data;
                console.log('success');
            },
            function(error) {
                console.log('something went wrong');
            }
        );
    }
}]);

.factory('Imgur', function($resource, $http) {
    return {
        albumList : $resource('https://api.imgur.com/3/account/:user/albums'),
        album : $resource('https://api.imgur.com/3/account/:user/album/:id')
    }
});

This approach however crashes my browser on every page load.

What is the right way to do this?

like image 763
Dan Kanze Avatar asked May 07 '13 01:05

Dan Kanze


2 Answers

So, you have ng-repeat="album in getAlbumList(user.name)", which is an Angular expression. What ng-repeat does is evaluates getAlbumList(user.name) on every digest. This is just like any other expression in a view, such as ng-show or whatever, and those expressions get evaluated all the time. If your expression is slow to evaluate hundreds of times, you shouldn't have it in an expression like this.

What you have here is an Ajax call in that function. Even if you somehow had a blocking synchronous Ajax call, it would be orders of magnitude too slow. Expressions should just access data already at hand, or maybe run simple code to sort and filter. They should never try to make Ajax calls.

But that's assuming it's synchronous Ajax, which this isn't. The expression simply calls getAlbumList and assumes the result is an array and uses it for ng-repeat. That function returns nothing, so it returns undefined, and you get nothing.

So to answer your question, what you should do is, put an empty array on scope, use that from the ng-repeat, and fill it in via Ajax. The beauty of Angular means the data will just "pop in" in the view once it's there. Here's some view code:

<ul>
  <li ng-repeat="album in albums">{{album.title}}</li>
</ul>

And some controller code:

$scope.albums = [];
Imgur.albumList.get({user:user},
    function(value) {
        $scope.albums = value.data;
        console.log('success');
    },
    function(error) {
        console.log('something went wrong');
    }
);

Which is basically the code you already had, just not run from a function, but run right in the constructor of the controller.

Edit

I think your fundamental misunderstanding is thinking that returning something from an ngResource callback will in turn return it from the containing function (getAlbumList). That's not the case. The containing function runs, returns nothing, then later on your callback runs, returns something, but no one is using that return value.

like image 120
jpsimons Avatar answered Oct 15 '22 21:10

jpsimons


<ul ng-controller="Users">
     <li ng-repeat="user in users">
       <ul ng-controller="Albums" ng-init="getAlbumList(user.name)">
          <li ng-repeat="album in albums">
           {{album.title}}
          </li>
       </ul>
     <li>
</ul>


.controller('Albums', ['$scope','Imgur', function($scope, Imgur) {
    $scope.getAlbumList = function(user) {
        Imgur.albumList.get({user:user},    
          function(value) {
                $scope.albums = value.data;
                console.log('success');
          },
          function(error) {
              console.log('something went wrong');
          }
      );
    }}]);

Try this. If not then check this question Reusable components in AngularJS

like image 34
Ketan Avatar answered Oct 15 '22 20:10

Ketan