Some of the common directives that use $watch / $watchCollection / $watchGroup internally:
- ng-model
- ng-bind / {{ }}
- ng-show & ng-hide
- ng-class
- ng-repeat
- ng-if
- ng-switch
- ng-include
Note that the only one that sets up a two-way binding is ng-model (scope -> view & view -> scope).
The others set up a one-way binding (scope -> view).
Simply exposing something on for example a controller“s $scope will not add a watcher.
For example, the following will not result in a watcher being added:
angular.module('myApp', []).controller('Controller', function MyCtrl($scope) {
$scope.value = 1;
});
Together with:
<body ng-app="myApp" ng-controller="Controller">
</body>
But if you replace the HTML with the following one watcher will be added:
<body ng-app="myApp" ng-controller="Controller">
<div>{{value}}</div>
</body>
Some common scenarios when the digest cycle is triggered:
- When
ng-click is evaluated
- When
ng-model changes (for example when typing in an input)
- By the
$http service
- In
$timeout and $interval
Note that there is one big difference between $apply and $digest:
Calling scope.$digest() will execute the watchers only on that scope and its children.
Calling scope.$apply() will trigger $digest on the $rootScope, which means all the scopes will be traversed and all watchers executed.
$apply also accepts an expression as an argument. This expression will be evaluated inside a try-catch statement and any exception will be passed on to the $exceptionHandler service.
$digest does not accept any arguments.
Usually you only call $digest instead of $apply when you are chasing micro optimizations and really know what you are doing.