How does the $apply() method work?

Loading

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() since setTimeout is outside AngularJS’s control.

Without $apply(), AngularJS won’t recognize the change, and the UI won’t update.


$apply() vs $digest()

MethodScopeUse 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 scopesUse 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.

Leave a Reply

Your email address will not be published. Required fields are marked *