Chances are if you have been using AngularJS for a little while that you have come across $scope.$apply()
at some point, whether it be your own code or someone else’s. What the heck is $scope.$apply() and why should you care?
To understand why we have $scope.$apply we have to understand that Javascript is turned based. When you write your Javascript code, it does not run all at once, code is run in blocks. So it is possible when you change a value within Angular and a $digest cycle has already been run, your changes will not be seen.
When you make a change outside of a non-Angular method, so a native DOM event or method in a third party library like jQuery, Angular does not know anything changed and as such, will not acknowledge anything has changed. All $scope.$apply does is basically says: “Hey Angular, a value changed bro, thought you should know, so you can tell your listener homies about it”
When you use $scope.$apply it will trigger a $digest cycle which ties into two-way binding which AngularJS uses quite heavily. Effectively $scope.$apply is a wrapper around $digest. Incorrect use of $apply can result in a “digest already in progress” error which means you tried using $apply when a $digest is already running.
Actions in AngularJS that trigger a $digest can include; in-built Angular directives like ng-repeat, ng-hide, ng-show, ng-click and even $http calls. If you try using $scope.$apply within one of these calls or even within a $timeout, you will get issues.
You should ideally only ever use $digest or $apply inside of an asynchronous call to let Angular know when you have made some changes as the official wiki details. And you should never use $apply or $digest within a controller, only within directives and services.
A classic example that does the runs is using a setTimeout (you would ideally use a $timeout but for example sakes):
setTimeout(function () {
$scope.$apply(function () {
$scope.message = "Timeout called!";
});
}, 3000);
In the above example, after 3 seconds, the timeout function will resolve itself and set the $scope variable “message” to ‘Timeout called!’ because we are updating code from a non-Angular method, we need to call $apply to tell Angular about the changes.
In a nutshell $scope.$apply tells Angular and any watchers that values have been changed and to go back and check if there are any new values. This keeps things within the Angular context regardless of how you made a change, like in a DOM event, jQuery method, etc.