98

If I have a directive that responds to the status of a particular attribute on the scope, and I want to change that attribute in my test and verify that it responds correctly, which is the best way of doing that change?

I've seen both these patterns:

scope.$apply(function() {
    scope.myAttribute = true;
});

and

scope.myAttribute = true;
scope.$digest();

What is the difference between them, and which is better and why?

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895

2 Answers2

207

scope.$digest() will fire watchers on the current scope, and on all of its children, too. scope.$apply will evaluate passed function and run $rootScope.$digest().

The first one is faster, as it needs to evaluate watchers for current scope and its children. The second one is slower, as it needs to evaluate watchers for$rootScope and all it's child scopes.

When an error occurs in one of the watchers and you use scope.$digest, it's not handled via $exceptionHandler service, so you need to handle exception yourself. scope.$apply uses a try-catch block internally and passes all exceptions to $exceptionHandler.

activedecay
  • 10,129
  • 5
  • 47
  • 71
T W
  • 6,267
  • 2
  • 26
  • 33
12

As the documentation itself mentions $digest cycle is peformed any time you do $scope.$apply. As per developer guide on scope

After evaluating the expression, the $apply method performs a $digest. In the $digest phase the scope examines all of the $watch expressions and compares them with the previous value.

And as per the Scope API documentation

Usually you don't call $digest() directly in controllers or in directives. Instead a call to $apply() (typically from within a directives) will force a $digest().

So you should not explicitly call $digest, you calling $apply method would trigger a digest cycle.

Jackson
  • 9,188
  • 6
  • 52
  • 77
Chandermani
  • 42,589
  • 12
  • 85
  • 88
  • 8
    this is not true as digest is sufficient for most of the cases where only the current scope and its children need to be evaluated. it is true that $scope.$apply calls $digest internally but it is very important to remember it will end up calling $rootScope.$digest() and hence very heavy – Srivathsa Harish Venkataramana Dec 29 '15 at 17:00