In AngularJS, the $digest
cycle is the mechanism responsible for detecting changes in the application and updating the UI accordingly. It is part of AngularJS’s two-way data binding, ensuring that changes in the Model (JavaScript objects) reflect in the View (HTML) and vice versa.
How Does the $digest
Cycle Work?
- Triggered Automatically – When an AngularJS event (e.g.,
ng-click
,ng-model
update,$http
response) occurs, the$digest
cycle starts. - Watches for Changes – It checks all watch expressions (
$scope.$watch
) to see if any data has changed. - Propagates Changes – If changes are found, Angular updates the View and triggers another check to ensure everything is updated correctly.
- Stops When Stable – The cycle repeats until no more changes are detected (usually 2-10 iterations).
Example of $digest
Cycle in Action
Let’s consider a simple example:
<div ng-app="myApp" ng-controller="MainController">
<p>Counter: {{ counter }}</p>
<button ng-click="increment()">Increment</button>
</div>
var app = angular.module("myApp", []);
app.controller("MainController", function ($scope) {
$scope.counter = 0;
$scope.increment = function () {
$scope.counter++; // Changes the Model
};
});
🔹 What Happens Internally?
- When the user clicks the button,
increment()
updates$scope.counter
. - This triggers the
$digest
cycle, which checks all$scope
variables. - Since
$scope.counter
has changed, the View updates automatically.
$digest
vs $apply
1️⃣ $digest()
- Runs the digest cycle only on the current
$scope
and its children. - Used when you want to manually trigger a limited update.
- Example: javascriptCopyEdit
$scope.$digest();
2️⃣ $apply()
- Runs the digest cycle on the entire application ($rootScope and all child scopes).
- Used when changes happen outside of AngularJS (e.g., inside
setTimeout
, jQuery). - Example: javascriptCopyEdit
$scope.$apply(function () { $scope.counter++; });
This ensures Angular is aware of the change.
Common Pitfalls with $digest
Cycle
1️⃣ $digest already in progress
Error
If you manually call $digest()
inside an AngularJS event (e.g., ng-click
), it conflicts with the existing cycle. Instead, use $apply()
:
Correct:
$scope.$apply(function () {
$scope.counter++;
});
Incorrect:
$scope.increment = function () {
$scope.counter++;
$scope.$digest(); // Error: $digest already in progress
};
2️⃣ Performance Issues with Large Applications
- Too many watchers (
$scope.$watch
) slow down performance. - Avoid deep object watching (
true
flag in$watch
). - Use one-time binding (
::
) when data does not change:<p>Name: {{ ::user.name }}</p>