$ watch没有像预期的那样多次开火

时间:2015-07-23 10:34:29

标签: javascript angularjs watch

如果您更改正在观看$watch次的变量,我希望x能够触发x次。在我放在一起的一个小例子中,我将变量$scope.foo的值改为3次,但关联的$watch只运行一次......

<html>
  <head>
    <title></title>
    <script src="https://code.angularjs.org/1.3.8/angular.js"></script>
  </head>
  <body ng-app='myApp'>

    <div ng-controller='MyCtrl'></div>

    <script>
      var myApp = angular.module('myApp', []);

      myApp.controller('MyCtrl', function($scope) {
          $scope.$watch('foo', function(oldVal, newVal) {
              console.log(oldVal, newVal);
          });

          $scope.foo = "foo";
          $scope.foo = "bar";
          $scope.foo = "baz";
      });


    </script>
  </body>
</html>

是否有人能够解释这是什么原因,或者我可以采取不同的方法来获得理想的结果?

我期待以下控制台输出:

undefined foo
foo bar
bar baz

但是......

baz baz

编辑:另一个例子

  myApp.controller('MyCtrl', function($scope, $timeout) {
      $scope.$watch('foo', function() {
          $scope.bar = 'bar';
      });

      $scope.foo = "foo";

      // now the value of $scope.foo has changed, I was expecting the $watch to have run at this point.
      // Apparently is has not because $scope.bar is still undefined. Accessing $scope.bar in a $timeout works, but is there a better way?
      console.log($scope.bar)
  });

3 个答案:

答案 0 :(得分:2)

$watch只会在每个角度$ digest周期中触发一次! (如果观看属性 - 最简单的情况)。

您对foo所做的三项更改都发生在同一周期内。而角度将比较循环前和循环后的值。

根据您的情况,您需要触发一个新周期,例如,更改$timeout内的值。

修改

对于你的例子,你可以做这样的事情

myApp.controller('MyCtrl', function($scope) {
    $scope.foo = "foo";
    // run on controller init
    fooWatch();
    // watch for changes
    $scope.$watch('foo', fooWatch);

    function fooWatch() {
        $scope.bar = 'bar';
    }
});

答案 1 :(得分:1)

因为每次更改范围内的变量时都不会运行$digest周期(幸运的是)。

但是当您使用$timeout时会触发它。

你的用例是什么?

在控制器中使用$watch进行BTW通常不是一种好的做法,而且很容易避免。

答案 2 :(得分:0)

角度变化太快,$timeout可以正常工作:

<html>
  <head>
    <title></title>
    <script src="https://code.angularjs.org/1.3.8/angular.js"></script>
  </head>
  <body ng-app='myApp'>

    <div ng-controller='MyCtrl'></div>

    <script>
      var myApp = angular.module('myApp', []);

      myApp.controller('MyCtrl', function($scope, $timeout) {
          $scope.$watch('foo', function(oldVal, newVal) {
              console.log(oldVal, newVal);
          });

          $scope.foo = "foo";
          $scope.foo = "bar";
          $scope.foo = "baz";
        
          $timeout(function(){
            $scope.foo = "foo";
          },0)        
          $timeout(function(){
            $scope.foo = "bar";
          },0)        
          $timeout(function(){
            $scope.foo = "baz";
          },0)
      });


    </script>
  </body>
</html>

请参阅How does AngularJS's $watch function work?