What is two-way data binding and the digest cycle in AngularJS?
Quick Answer
Two-way binding keeps the view and the model in sync: ng-model updates the scope when the user types, and the scope updates the DOM when code changes it. AngularJS achieves this by dirty checking — during the digest cycle it compares every watched expression's current value to its previous value and updates the DOM where they differ, looping until nothing changes (stable).
Two-way binding means ng-model links a form field and a scope property in both directions — type in the box and the model updates, change the model in code and the box updates. Under the hood AngularJS does dirty checking. Every binding registers a watch, and whenever something might have changed the model, Angular runs the digest cycle: it walks all the watchers, compares each value to its last value, updates the DOM where they differ, and repeats until nothing changes. The catch is that changes from outside Angular's world — a plain setTimeout or a jQuery callback — don't trigger a digest, so you wrap them in $scope.$apply. And because every digest checks every watcher, a page with thousands of bindings gets slow, which is why one-time bindings and track by matter.
Each binding registers a $watch. When something might have changed the model — a DOM event Angular knows about, an $http response, a $timeout — Angular runs $digest on the scope tree: it evaluates every watcher, and if any value changed it applies the change and runs the loop again (up to 10 times) until the watchers are stable.
- Changes made outside Angular (a raw
setTimeout, a jQuery event, a third-party callback) aren't seen until you call$scope.$apply()(or$scope.$applyAsync()). - Performance — every digest evaluates every watcher on the page. Thousands of bindings (big
ng-repeatlists) make each digest slow. Mitigations: one-time binding{{::value}},track by, pagination, fewer watchers,ng-ifinstead ofng-showfor large hidden subtrees.