What are $watch, $digest and $apply in AngularJS?
Quick Answer
$watch(expr, fn) registers a listener that fires during a digest when expr's value changes. $digest runs the dirty-checking loop on a scope tree. $apply(fn) runs fn then triggers a digest on the root scope — you call it to bring changes made outside Angular (a raw setTimeout, a jQuery event) into the digest.
$watch registers a callback that Angular runs during a digest whenever the watched expression changes. $digest is the dirty-checking loop that evaluates all the watchers on a scope and its children until nothing changes. $apply is what you call when you've changed model data from outside Angular's world — a plain setTimeout, a third-party callback — it runs your function and then kicks off a digest so the view updates. The error people hit is calling $apply inside an ng-click, which is already inside an $apply — then you get “$apply already in progress.”
- Angular's own directives (
ng-click,$http,$timeout) wrap your code in$applyalready — don't double-wrap or you get “$apply already in progress”. $evalAsyncschedules work for the current-or-next digest;$applyAsynccoalesces multiple external changes into one digest.$watchCollection(shallow) and$watch(expr, fn, true)(deep) for objects/arrays — deep watches are expensive.- Prefer
$scope.$digest()(local subtree) over$apply()(whole tree) when you know the scope.