I'm working with the Soundcloud JS SDK to bring my Soundcloud favorites into a simple Angular app.
I wasn't able to get the user favorites to import in correctly until I used $scope.$apply
.
function TopListCtrl($scope, $http, $modal) {
$scope.getData = function(sc_user) {
SC.get('/users/'+ sc_user +'/favorites', {limit: 200}, function(tracks){
$scope.$apply(function() {
if (Object.getOwnPropertyNames(tracks).length > 1) {
$scope.likes = tracks;
$scope.sortField = 'like.favoritings_count';
$scope.reverse = true;
$scope.sc_user = sc_user;
}
else {
alert("That user has 0 Soundcloud likes. So sad...")
}
}).error(function (data, status, headers, config) {
alert("Something went awry with that request. Double check that's a real Soundcloud username");
})
});
}
If you don't use $scope.apply, it doesn't work (and says SC.get not defined).
I'd like to understand a bit better why $scope.$apply
is necessary. I ask this because when I was just using the http api, I didn't need it.
function TopListCtrl($scope, $http, $modal) {
$scope.getData = function(sc_user) {
var url = 'http://api.soundcloud.com/users/'+ sc_user +'/favorites.json?client_id=0553ef1b721e4783feda4f4fe6611d04&limit=200&linked_partitioning=1&callback=JSON_CALLBACK';
$http.jsonp(url).success(function(data) {
if (Object.keys(data.collection).length > 0) {
$scope.likes = data;
$scope.sortField = 'like.favoritings_count';
$scope.reverse = true;
$scope.sc_user = sc_user;
}
else {
alert("That user has 0 Soundcloud likes. So sad...")
}
}).error(function (data, status, headers, config) {
alert("Something went awry with that request. Double check that's a real Soundcloud username");
});
}
Usually angular knows about the code that's executing because you're the one providing the function callbacks but it's angular that's actually calling them. After angular calls a function, it will call $apply sometime later to trigger a $digest cycle.
If you don't know what a $digest cycle is, the concept is simple. During the $digest phase, angular will do a dirty check on every scope variable that's been set up with a $watch handler and check if it's changed; if it has angular will call its the corresponding $watch handler to update the view.
Getting back to the original question - when angular knows about your code, it will trigger a $digest cycle for you - so there is no need to call $apply explicitly. If you handle a jquery event, that's a different story. Angular has no idea that a $digest might be needed - how can it? So $apply is needed to trigger the $digest manually.
I know that you've already received the correct response to your question. I thought I'd also mention that it's not terribly difficult to use $http to make requests to the Soundcloud API, so that you won't need to use $scope.$apply. Here are mine:
Pixelbits' answer and an article by Jim Hoskins on $scope.$apply helped me understand this a little better. Here's the crucial point per my original question:
I'm still hazy on turns but I get the crucial point is that the method (
SC.get
in my case) isn't part of the AngularJS library so I, therefore, need to use$apply
.(At least I think I get it)