d-_-b d-_-b - 14 days ago 4
AngularJS Question

Why do I need $rootScope.$apply when inside $rootScope.$on?

Why is

$rootScope.$apply()
needed in this example to update elements using
ng-hide
on the page?

In my experience whenever I put
$scope.$apply()
inside a
$scope.$watch
I get the "digest already in progress" error. Is this different?

app.component('myComponent', {
controller: function(){
$scope.visible = false;

$rootScope.$on('someEvent', function(){
$scope.visible = true;
$rootScope.$apply(); // why?
});
}
});

Answer

Callback registered with $rootScope.$on is triggered by either $rootScope.$broadcast or $rootScope.$emit. If you explore these methods source code you will see that these methods by itself do not trigger $digest cycle (dirty-checking). That means, that $digest should be triggered either by the code that calls $broadcast or $emit, or inside a callback registered with $rootScope.$on.

Usually, it's better to assume that callback is triggered inside $digest loop and it means that callback call should be wrapped with $apply, as in:

$rootScope.$apply($rootScope.$broadcast('event', data));

This is consistent with what angular best practices suggest:

$scope.$apply() should occur as close to the async event binding as possible.