5

I have tried looking around at other $rootScope:infdig questions here and couldn't find one that really explained it to me well, or that I understood. Same with the AngularJs docs. I hope someone can help.

I have function that I made on the $scope that takes one parameter and calls an api GET request and returns a json object with just and "id" and a "name". This function then returns the name from the object back to the directive that calls it.

The function gets called from the directive but once it does it gets stuck in an error of a hundred of these "rootScope:infdig" per second. The directive also never renders the text of the returned "name". I know the http call works because I log the "name" in the console after.

Error Screen

Here is my controller:

owlyfm.controller('landingPageController', [ "$scope", "$log", "$http", "$location", "apiUrlsService", function ($scope, $log, $http, $location, apiUrlsService) {

 $http.get("https://api.backand.com:443/1/objects/Albums?pageSize=3&pageNumber=1&deep=true&relatedObjects=true")
    .success( function(result){
        $scope.featuredAlbums = result.data;
        //$log.info($scope.featuredAlbums);
    })
    .error( function(data, status){
        $log.error(data);
    });

    $scope.getAlbumArtist = function(artistId){

      $http.get("https://api.backand.com:443/1/objects/Artists/" + artistId)
        .success(function(result){
          var artistsName = result.name;
          $log.info(artistsName);
          return artistsName;
        });
    }
}]);

Here is where I created the directive:

owlyfm.directive("featuredAlbum", function(){

return{
    restrict: 'E',
    templateUrl: 'directives/featuredAlbum.html',
    scope: {
        albumObject: "=",
        getAlbumArtistFunction: "&"
    }
  }
});

Here is where I call the directive in the view

<div class="row fluid-container" >
    <featured-album ng-repeat="featuredAlbum in featuredAlbums" album-object="featuredAlbum" get-album-artist-function="getAlbumArtist(album)" class="col-md-4" ></featured-album>
</div>

And here is the directive itself:

    <div class="featuedAlbum">

        <div>
            <img class="img-responsive" ng-src=" {{albumObject.albumArtUrl}} "/>
        </div>

        <h4>{{ albumObject.name }}</h4>
        <h5>{{ getAlbumArtistFunction( { album: albumObject.Artists } ) }}</h5>
        <h6>{{ albumObject.releaseDate }}</h6>

    </div>

What I'm Doing

To wrap up, what I am doing is calling the api to get an album object, (I am using "Backand" BTW) Once I get this album object I render the <img> and <h> tags with the data I receive. That is working fine.

The album object has and ID, name, Date, imgUrl, and "Artists" (which is just an id for the artist). I then use this "artists" id to make another call to get the actual Artist object that is associated with it. This is where the problem arises.

The Problem

It is the http call for the artist object that is causing the loop of errors. Even though I can see in the log that it is getting the json object of the artists, it will not send it to the directive.

What I've Researched

I have read that there are problems with using ng-repeat with functions from a directive. However, I don't quite fully understand why and how it applies here nor do I know how I would change it to do what I am trying to achieve. All of the other questions on here are a little above my head.

If anyone could help me out that would be very appreciated.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • forget about angular 1, angular 2 is coming and in beta version now! – Kevin Simple Jan 11 '16 at 04:22
  • My suggestion would be, don't make any http requests in a function called in view: it would be called hundreds of times. And I think the infinity digest issue should be gone after that. – Haocheng Jan 11 '16 at 04:32
  • 2
    This seems to be a case of a race condition. `$http` is async and returns a promise. You are iterating through the array, and for each row in your array, issuing an `$http` call; each call that is returned will initiate a `$digest` cycle, which will then re-iterate through the array and re-initiate the `$http` calls, effectively infinitely looping your code. – Claies Jan 11 '16 at 04:37
  • you *might* be able to solve this by using a `track by` clause on the `ng-repeat`, by using the one time binding `::` syntax for `::getAlbumArtistFunction`, or both. However, making this many `$http` calls in series like this is a performance bottleneck, and you would be better to design a specific endpoint on the server that can return the combined information in one call. – Claies Jan 11 '16 at 04:40
  • Thanks for the help guys. @Haocheng Thanks for your input, how would you suggest I make this call to render the data in the view? – Joshua Shoemaker Jan 11 '16 at 15:43
  • And @Claies that is what I would prefer but I am still getting use to "Backands" api service. When ever I call an object I get the ability to call objects related to it, but I have trouble digging into the json to retrieve them. The objects I call are always in the object "data" and then the related objects are always in another object called "relatedObjects" that is not inside of "data" – Joshua Shoemaker Jan 11 '16 at 15:49
  • hi, @JoshuaShoemaker getting the children objects is possible by using query parameter deep=true. Using the deep is possible only on a single item implementing "lazy load". After you get a list of items just call to API /1/objects/items/1?deep=true and you will have all the data – Itay Jan 12 '16 at 23:28

1 Answers1

1

As said in comments, it's not a good idea to call a function that will fetch data from server inside view, because it will call multiple times, when you need it to be called only once.

You can add a property of "artistName" that will be set in "featuredAlbum" constructor.

owlyfm.controller('featuredAlbumController', [ "$scope","$http",function ($scope, $http) { $http.get("https://api.backand.com:443/1/objects/Artists/" + $scope.artistId) .success(function(result){ $scope.artistName = result.name; }); }]);

So, $http will be called only once, on controller first time run.

Ygalbel
  • 5,214
  • 1
  • 24
  • 32