Updating $scope Data in Asynchronous Functions
One of the many lovely things about Angular is the fluid two-way data binding that we get with the framework. Although not entirely perfect when it comes down to performance, it saves us quite a lot of time and effort when writing web applications.
When it comes to asynchronousy, however, it should be noted that doing changes to your $scope
data does not propagate to the view implicitly (!). In other words, if you do a change to a $scope
variable from asynchronous context, the change is not reflected in the view. Let’s look at an example. Consider the following controller that uses JavaScript’s asynchronous setInterval
function to update a counter every second:
function Ctrl ($scope) {
$scope.counter = 0;
setInterval(function() {
$scope.counter++;
}, 1000);
}
This code looks pretty good and dandy, right? Unfortunately, no. Although the counter does get updated every second, it does not propagate the change to the view. There are a couple of ways to solve this issue.
Invoking $apply Manually
The simplest and most straightforward way is to invoke $apply
manually in the asynchronous context. Consider the following change to our initial example (lines 5 - 7):
function Ctrl ($scope) {
$scope.counter = 0;
setInterval(function() {
$scope.$apply(function () {
$scope.counter++;
});
}, 1000);
}
This change will force the counter updates through to the view.
Using Angular’s Asynchronous Services
This approach is case specific. For instance, you can use the services $interval
or $timeout
, which actually behind the scenes invoke $apply
- relieving you from doing so manually. Considering our initial example, we can therefore inject and use $interval in our controller instead:
function Ctrl ($scope, $interval) {
$scope.counter = 0;
$interval(function () {
$scope.counter++;
}, 1000);
}
As the previous approach, this will propagate the counter updates to the view. I recommend using Angular’s services wherever this is possible and seems appropriate to the case at hand. However, always keep in mind that such services invoke $apply
for you behind the scenes.
Hope you enjoyed this Sunday's little reading! :)