Powered By Blogger

Wednesday, July 15, 2015

$watch, $digest and $apply [Angular]

$watch() - This function is used to observe changes in a variable on the $scope. It accepts three parameters: expression, listener and equality object, where listener and equality object are optional parameters.
$watch(watchExpression, listener, [objectEquality]);
 <html>   
 <head>   
 <title>AngularJS Watch</title>  
 <script src="lib/angular.js"></script>   
 <script>   
 var myapp = angular.module("myapp", []);   
 var myController = myapp.controller("myController", function ($scope) {   
     $scope.name = 'theprogrammingtree.com';   
     $scope.counter = 0;   
    //watching change in name value   
    $scope.$watch('name', function (newValue, oldValue) {   
        $scope.counter = $scope.counter + 1;   
    });   
 });   
 </script>   
 </head>   
 <body ng-app="myapp" ng-controller="myController">   
 <input type="text" ng-model="name" /> <br /><br />   
 Counter: {{counter}}   
 </body>   
 </html>  

$digest() - This function iterates through all the watches in the $scope object, and its child $scope objects (if it has any). When $digest() iterates over the watches, it checks if the value of the expression has changed. If the value has changed, AngularJS calls the listener with the new value and the old value.

The $digest() function is called whenever AngularJS thinks it is necessary. For example, after a button click, or after an AJAX call. You may have some cases where AngularJS does not call the $digest() function for you. In that case you have to call it yourself.

 <html>   
 <head>   
 <script src="lib/jquery-1.11.1.js"></script>   
 <script src="lib/angular.js"></script>   
 </head>   
 <body ng-app="app">   
 <div ng-controller="Ctrl">   
   <button class="digest">Digest my scope!</button> <br />   
   <h2>obj value : {{obj.value}}</h2>   
 </div>   
 <script>   
 var app = angular.module('app', []);   
 app.controller('Ctrl', function ($scope) {   
     $scope.obj = { value: 1 };   
     $('.digest').click(function () {   
       console.log("digest clicked!");   
       console.log($scope.obj.value++);   
      //update value   
      $scope.$digest();  
     });   
 });   
 </script>   
 </body>   
 </html>  

$apply() - Angular do auto-magically updates only those model changes which are inside AngularJS context. When you do change in any model outside of the Angular context (like browser DOM events, setTimeout, XHR or third party libraries), then you need to inform Angular of the changes by calling $apply() manually. When the $apply() function call finishes AngularJS calls $digest() internally, so all data bindings are updated.

 <html>   
 <head>   
 <title>AngularJS Apply</title>   
 <script src="lib/angular.js"></script>   
 <script>   
 var myapp = angular.module("myapp", []);   
 var myController = myapp.controller("myController", function ($scope) {   
    $scope.datetime = new Date();   
    $scope.updateTime = function () {   
      $scope.datetime = new Date();   
    }   
    //outside angular context  
    document.getElementById("updateTimeButton").addEventListener('click', function (){  
      //update the value   
      $scope.$apply(function () {   
       console.log("update time clicked");     
       $scope.datetime = new Date();   
       console.log($scope.datetime);   
     });   
    });   
 });   
 </script>   
 </head>   
 <body ng-app="myapp" ng-controller="myController">   
 <button ng-click="updateTime()">Update time - ng-click</button>   
 <button id="updateTimeButton">Update time</button> <br />   
 {{datetime | date:'yyyy-MM-dd HH:mm:ss'}}   
 </body>   
 </html>  

$digest() is faster than $apply(), since $apply() triggers watchers on the entire scope chain i.e. on the current scope and its parents or children (if it has) while $digest() triggers watchers on the current scope and its children(if it has).

When error occurs in one of the watchers, $digest() cannot handled errors via $exceptionHandler service, In this case you have to handle exception yourself.
While $apply() uses try catch block internally to handle errors and if error occurs in one of the watchers then it passes errors to $exceptionHandler service.

Pseudo-code for $apply()
 function $apply(expr) {  
    try {   
       return $eval(expr);   
    } catch (e) {   
       $exceptionHandler(e);   
    } finally {   
       $root.$digest();   
    }   
 }  

No comments:

Post a Comment