Reputation: 4267
So I have an HTML template inside which I have following angular expression {{player.score}}
. The initial score of the player that is stored in a scope object is correctly rendered in the place of the expression.
Now, I have a button click on which this score needs to be updated. If I simple update the players score with a hardcoded value it works correctly:
$scope.updateScore = function (){
$scope.player.score = 1000; //this is updated without any issues
};
But my problem is that my player score is a complicated calculation, which needs me to use _.defer
. So when I wrap my earlier code (for testing) inside _.defer
it does not work:
$scope.updateScore = function (){
_.defer(function() {
$scope.player.score = 5000; //this is not updated...
});
};
The way I understand _.defer
it is just underscores wrapper for setTimeout
. I would expect that after whatever delay _.defer
uses, when it finally gets around to updating the score, then it will get reflected in the HTML due to the Angular two-way binding.
But this is not happening only when _.defer
is used, else it works as expected. Also _.defer
is updating the Angular object because if I do a console.log(player.score)
in the deferred code, then after a few seconds in the console I do see the update score (5000).
Can any angular/Javascript experts help me understand what I am doing incorrect and how I can fix it. Please note that removing _.defer
is not really an option because of various technical/legacy reasons.
I am just trying to figure out why when the object is updated in a deferred manner, the Angular does not update the view.
Any pointers are greatly appreciated.
Upvotes: 3
Views: 527
Reputation: 16609
_.defer
takes the code out of the scope of the angular digest, because it internally calls setTimeout
.
You either need to manually kick off a digest inside the deferred function so angular rebinds at that point, using $scope.$apply:
$scope.updateScore = function (){
_.defer(function() {
player.score = 5000;
$scope.$apply();
});
};
or you need to keep the callback inside the angular scope, probably by using $timeout
(but remember to inject $timeout
into your controller/directive):
$scope.updateScore = function (){
$timeout(function() {
player.score = 5000;
}, 1); // or 0, but _.defer passes 1
};
I would go with option 2 from preference, and I personally can't see how using _.defer
can be required over this, but of course it is up to you.
Upvotes: 1
Reputation: 12025
Angular doesn't "know" about this defer so even if the value gets updated, it won't appear in the view until the next digest loop. You can inject $timeout to your controller and use it like this:
_.defer(function() {
$timeout(function() {
$scope.player.score = 5000; //this is not updated...
});
});
You should also read about deferred objects in angular (https://docs.angularjs.org/api/ng/service/$q)
Upvotes: 2