What are $watch, $digest and $apply in AngularJS?

AngularJS Data Binding Advanced 3–5 Yrs5+ Yrs Conceptual 1 min read

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 $apply already — don't double-wrap or you get “$apply already in progress”.
  • $evalAsync schedules work for the current-or-next digest; $applyAsync coalesces 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.