![]()
The $apply() method in AngularJS is used to manually trigger a digest cycle ($digest) when changes occur outside AngularJS’s scope, ensuring the UI updates correctly.
By default, AngularJS automatically triggers the digest cycle when handling events like ng-click or ng-model. However, if changes happen outside of AngularJS (e.g., inside setTimeout, jQuery, or external APIs), Angular doesn’t detect them. This is where $apply() helps.
How $apply() Works Internally
1️⃣ Executes a function passed to it (if provided).
2️⃣ Calls $rootScope.$digest(), running the digest cycle for the entire app.
3️⃣ Detects changes and updates the View accordingly.
Example: $apply() in Action
Scenario: Updating UI with setTimeout
AngularJS doesn’t detect changes inside setTimeout. We must use $apply() to inform AngularJS.
<div ng-app="myApp" ng-controller="MainController">
<p>Counter: {{ counter }}</p>
<button ng-click="increment()">Increment</button>
<button ng-click="delayedIncrement()">Delayed Increment</button>
</div>
var app = angular.module("myApp", []);
app.controller("MainController", function ($scope) {
$scope.counter = 0;
// Normal AngularJS Event (No Need for $apply)
$scope.increment = function () {
$scope.counter++;
};
// Using setTimeout (Requires $apply)
$scope.delayedIncrement = function () {
setTimeout(function () {
$scope.$apply(function () {
$scope.counter++; // Manually trigger digest cycle
});
}, 2000);
};
});
Explanation:
increment()works fine because AngularJS automatically triggers the digest cycle.delayedIncrement()requires$apply()sincesetTimeoutis outside AngularJS’s control.
Without $apply(), AngularJS won’t recognize the change, and the UI won’t update.
$apply() vs $digest()
| Method | Scope | Use Case |
|---|---|---|
$apply() | Calls $digest() on $rootScope (entire app) | Use when changes occur outside AngularJS (e.g., setTimeout, jQuery, external APIs). |
$digest() | Runs only on the current scope and child scopes | Use when you want to trigger a limited digest cycle (avoid performance overhead). |
Example using $digest():
setTimeout(function () {
$scope.counter++;
$scope.$digest(); // Only updates the current scope
}, 2000);
This may cause “$digest already in progress” errors if called inside an Angular event.
Common Issues with $apply()
1️⃣ “Digest already in progress” Error
If $apply() is used inside an event that already runs a digest cycle, it causes an error.
Incorrect:
$scope.increment = function () {
$scope.counter++;
$scope.$apply(); // Error: $digest already in progress
};
Solution: Remove $apply() since AngularJS already runs the digest cycle:
$scope.increment = function () {
$scope.counter++; // No need for $apply
};
2️⃣ Performance Considerations
$apply()triggers a global digest cycle, which can be expensive for large applications.- Prefer local
$digest()where possible to limit scope updates. - Use one-time binding (
::) when data is static to reduce digest checks:<p>Name: {{ ::user.name }}</p>
Key Takeaways
Use $apply() when modifying $scope outside AngularJS (e.g., in setTimeout, jQuery, or external libraries).
Avoid calling $apply() inside AngularJS event handlers (like ng-click).
Use $digest() for performance optimization when needed.
