user2200321
user2200321

Reputation: 445

ng-repeat repeats, but is empty

I'm using the Soundcloud API to fetch tracks for a query typed into a searchbox like so:

$scope.tracks = [];

$scope.updateResults=function(song){
        if(song.length==0){
            $scope.tracks = [];
        }
        if(song.length>3){
            SC.get('/tracks', { q: song, license: 'cc-by-sa' }, function(tracks) {
                $scope.tracks = tracks;
                            //$scope.$apply() doesn't work either
            });
        }
    }

$scope.updateResults is called whenever something is typed into the searchbar. This all works fine. I've even tried logging $scope.tracks, which is an array, and it is populated with the tracks matching the search result. According to the Soundcloud API reference, each track has a title property. I tested this by doing:

console.log($scope.tracks[0].title), and I got a nice string with the title.

Now in my ng-repeat, which is written like so:

<ul>
    <li ng-repeat="track in tracks">{{track.title}}</li>
</ul>

I get several bullet points but they are all empty. In other words {{track.title}} doesn't exist? I've tested that this is a valid property. Additionally, I know that $scope.tracks is being populated because there are indeed list items, but they are all empty.

Thanks for any help!

EDIT: I did some research on ng-repeat and learned that it watches for updates such as .push()... should still not explain this weird behavior, but it might help identify the problem.

Upvotes: 1

Views: 295

Answers (1)

Harry Hedger
Harry Hedger

Reputation: 371

This isn't going to be the most technical explanation of what's going on, so I appreciate all edits. Since the Soundcloud Javascript SDK doesn't use $http to get the tracks, the scope doesn't know it needs to update when SC.get returns the tracks. In other words, even though $scope.tracks is populated, it doesn't know to update the view. I would recommend writing a service that handles all GET/POST/PUT/DELETE requests to Soundcloud. Here is a simple example using callbacks:

.factory('Soundcloud', function($http, $rootScope, $timeout, $q) {

  var request = function(method, path, params, callback) {
    params.client_id = sc.soundcloud.client_id;
    params.oauth_token = sc.soundcloud.access_token;

    $http({
      method: method,
      url: sc.soundcloud.api.host + path,
      params: params
    })
    .success(callback);
  };

  return {
    get: function(path, params, callback) {
      request('GET', path, params, callback);
    },

    put: function(path, params, callback) {
      request('PUT', path, params, callback);
    },

    post: function(path, params, callback) {
      request('POST', path, params, callback);
    },

    delete: function(path, params, callback) {
      request('DELETE', path, params, callback);
    }
  };
})

Once you inject the service into your controller, you get tracks like this:

Soundcloud.get('/tracks', {limit: 5}, function(tracks) {
  $scope.tracks = tracks;
});

Just set up where the service gets your client_id and oauth_token. Then the path is whatever endpoint you want and params is whatever parameters you want to pass to SC.

Upvotes: 1

Related Questions