How do I use $scope.$watch and $scope.$apply in AngularJS?

前端 未结 6 2029
栀梦
栀梦 2020-11-21 15:36

I don\'t understand how to use $scope.$watch and $scope.$apply. The official documentation isn\'t helpful.

What I don\'t understand specifi

6条回答
  •  灰色年华
    2020-11-21 15:58

    AngularJS extends this events-loop, creating something called AngularJS context.

    $watch()

    Every time you bind something in the UI you insert a $watch in a $watch list.

    User: 
    Password: 
    

    Here we have $scope.user, which is bound to the first input, and we have $scope.pass, which is bound to the second one. Doing this we add two $watches to the $watch list.

    When our template is loaded, AKA in the linking phase, the compiler will look for every directive and creates all the $watches that are needed.

    AngularJS provides $watch, $watchcollection and $watch(true). Below is a neat diagram explaining all the three taken from watchers in depth.

    angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
    function MyCtrl($scope,$timeout) {
      $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];
    
      $scope.$watch("users", function() {
        console.log("**** reference checkers $watch ****")
      });
    
      $scope.$watchCollection("users", function() {
        console.log("**** Collection  checkers $watchCollection ****")
      });
    
      $scope.$watch("users", function() {
        console.log("**** equality checkers with $watch(true) ****")
      }, true);
    
      $timeout(function(){
         console.log("Triggers All ")
         $scope.users = [];
         $scope.$digest();
    
         console.log("Triggers $watchCollection and $watch(true)")
         $scope.users.push({ name: 'Thalaivar'});
         $scope.$digest();
    
         console.log("Triggers $watch(true)")
         $scope.users[0].name = 'Superstar';
         $scope.$digest();
      });
    }
    

    http://jsfiddle.net/2Lyn0Lkb/

    $digest loop

    When the browser receives an event that can be managed by the AngularJS context the $digest loop will be fired. This loop is made from two smaller loops. One processes the $evalAsync queue, and the other one processes the $watch list. The $digest will loop through the list of $watch that we have

    app.controller('MainCtrl', function() {
      $scope.name = "vinoth";
    
      $scope.changeFoo = function() {
          $scope.name = "Thalaivar";
      }
    });
    
    {{ name }}
    
    

    Here we have only one $watch because ng-click doesn’t create any watches.

    We press the button.

    1. The browser receives an event which will enter the AngularJS context
    2. The $digest loop will run and will ask every $watch for changes.
    3. Since the $watch which was watching for changes in $scope.name reports a change, it will force another $digest loop.
    4. The new loop reports nothing.
    5. The browser gets the control back and it will update the DOM reflecting the new value of $scope.name
    6. The important thing here is that EVERY event that enters the AngularJS context will run a $digest loop. That means that every time we write a letter in an input, the loop will run checking every $watch in this page.

    $apply()

    If you call $apply when an event is fired, it will go through the angular-context, but if you don’t call it, it will run outside it. It is as easy as that. $apply will call the $digest() loop internally and it will iterate over all the watches to ensure the DOM is updated with the newly updated value.

    The $apply() method will trigger watchers on the entire $scope chain whereas the $digest() method will only trigger watchers on the current $scope and its children. When none of the higher-up $scope objects need to know about the local changes, you can use $digest().

提交回复
热议问题