AngularJS maintains synchronization between the model (data) and the view (UI) through its digest cycle. The digest cycle is responsible for detecting changes in scope variables and updating the view accordingly.
Normally, AngularJS automatically triggers the digest cycle when using built-in directives (ng-model
, ng-click
, etc.) or $http
requests. However, in certain cases (such as asynchronous operations or third-party event listeners), Angular does not detect changes automatically.
In such cases, we can manually trigger the digest cycle using $scope.$digest()
or $scope.$apply()
.
1. What is $scope.$digest()
?
$scope.$digest()
is a manual method that runs the digest cycle only for the current scope and its children. This means it does not propagate to parent scopes, making it more efficient in certain cases compared to $scope.$apply()
.
Syntax:
$scope.$digest();
Method | Scope Affected | Triggers $watch ? |
---|---|---|
$scope.$digest() | Affects only the current scope and child scopes | Yes |
$scope.$apply() | Affects entire app (root scope) | Yes |
2. When to Use $scope.$digest()
?
Use $scope.$digest()
when:
✔ You want to update only the current scope and its child scopes.
✔ You need a more efficient alternative to $scope.$apply()
when you don’t want to trigger a full app-wide digest cycle.
✔ You are updating the scope in custom event listeners or third-party libraries.
3. Example Without $scope.$digest()
(Issue)
If an event listener modifies $scope.message
, Angular does not detect changes automatically.
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
document.getElementById('updateBtn').addEventListener('click', function() {
$scope.message = "Button Clicked!";
console.log($scope.message); // UI does NOT update
});
});
<div ng-controller="MyController">
<p>{{ message }}</p>
<button id="updateBtn">Click Me</button>
</div>
Problem:
- The UI does not update when clicking the button because Angular doesn’t detect changes in the scope.
4. Fixing with $scope.$digest()
Manually trigger the digest cycle after modifying $scope.message
.
app.controller('MyController', function($scope) {
document.getElementById('updateBtn').addEventListener('click', function() {
$scope.message = "Button Clicked!";
$scope.$digest(); // Manually trigger digest cycle
});
});
Fix Explanation:
$scope.$digest()
triggers a digest cycle for the current scope, updating the UI immediately.
5. Difference Between $scope.$digest()
and $scope.$apply()
Feature | $scope.$digest() | $scope.$apply() |
---|---|---|
Scope Affected | Only current scope & child scopes | Entire app (root scope) |
Efficiency | More efficient | Less efficient (triggers a global digest cycle) |
Use Case | Local updates, event listeners | Async updates, external events |
Example Using $scope.$apply()
(Alternative Fix)
app.controller('MyController', function($scope) {
document.getElementById('updateBtn').addEventListener('click', function() {
$scope.$apply(function() {
$scope.message = "Button Clicked!";
});
});
});
Why use $apply()
?
$apply()
wraps the code inside a function, ensuring automatic change detection across the entire application.
6. Handling Asynchronous Code (setTimeout & setInterval)
When working with asynchronous functions like setTimeout()
, Angular does not detect changes automatically.
Example Without $scope.$digest()
(Issue)
app.controller('MyController', function($scope) {
setTimeout(function() {
$scope.message = "Updated after 3 seconds!";
}, 3000);
});
Problem:
- The UI does not update because
setTimeout()
runs outside Angular’s digest cycle.
Solution With $scope.$digest()
app.controller('MyController', function($scope) {
setTimeout(function() {
$scope.message = "Updated after 3 seconds!";
$scope.$digest(); // Manually trigger digest cycle
}, 3000);
});
Fix Explanation:
$scope.$digest()
ensures Angular runs a digest cycle after modifying$scope.message
.
7. Handling AJAX Requests
When making AJAX calls using raw JavaScript (fetch()
or XMLHttpRequest
), Angular does not detect changes automatically.
Example Without $scope.$digest()
(Issue)
app.controller('MyController', function($scope) {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(data => {
$scope.todo = data;
});
});
Problem:
- The UI does not update because Angular doesn’t detect the change.
Solution With $scope.$digest()
app.controller('MyController', function($scope) {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(data => {
$scope.todo = data;
$scope.$digest();
});
});
Fix Explanation:
$scope.$digest()
forces the UI to reflect the new data.
8. Avoiding $digest()
Inside $apply()
Calling $digest()
inside $apply()
causes an error:
$scope.$apply(function() {
$scope.$digest(); // Error: $digest already in progress
});
Fix: Remove $digest()
, as $apply()
already triggers a digest cycle.
9. Performance Considerations
Use $digest()
instead of $apply()
when you only need to update a specific scope, as it is more efficient.
Avoid calling $digest()
too frequently in loops or real-time updates, as it can impact performance.
For better performance, use $timeout()
instead of $digest()
when updating asynchronously.