Angular`watch`表现不如预期

时间:2014-10-10 13:18:55

标签: javascript angularjs

我有以下代码片段

function MyCtrl($scope, $log){

  $scope.name = 'guy';
  $scope.guy = {};


  function myWatch(){
    return function(newValue, oldValue){
      $log.info('these are the values',newValue, oldValue);

      if ( newValue === oldValue ){
        $log.info('they are the same');
      }
    }
  }

  $scope.$watch('guy',myWatch(), true);

  $scope.guy = { 'hello' : 'world' };

}

你可以run on plunkr - 寻找控制台版画!

这个想法是:

  • 为范围属性guy
  • 分配值
  • 在该属性上设置$watch
  • 将另一个值分配给guy
  • 期望newValueoldValue不同,并且在控制台日志中看不到they are the same打印 - 失败
    • 更具体地说,我希望oldValue{},newValue为{ 'hello':'world' }

我做错了什么,如何在需要时实现这个逻辑?

2 个答案:

答案 0 :(得分:3)

由于手表被评估为摘要周期的一部分,因此无需观察其他更改。我创建了一个在函数中更改guy的示例,通过单击按钮调用。

我还将watch函数调整为函数而不是函数返回函数。

function myWatch(newValue, oldValue){
  $log.info('these are the values',newValue, oldValue);

  if ( newValue === oldValue ){
    $log.info('they are the same');
  }    
}

$ scope。$ watch('guy',myWatch,true);

http://plnkr.co/edit/qCyvyLyNDscdFcQ3rsUj?p=preview

答案 1 :(得分:1)

我相信您遇到了计时问题,在值更改之前未完全设置手表,并且最终运行摘要时,如果您执行此操作,则值确实相同:

$timeout(function(){
   $scope.guy = { 'hello' : 'world' };
},3000,true); 

这将为您提供足够的时间来设置手表,并在稍后的时间点看到更改。有了这个改变,你的期望应该得到满足。

修改以进一步说明$ watch和digest周期:

无论被观察的值是否发生变化,都会在每个$watch上调用{p> $digest cycle,但listener仅在第一个$digest周期调用,但是在观察到的值发生变化之前不会被调用。此外,手表可以在每个$digest周期中运行多次,因此在第一个周期中可能会多次调用listener

Documentation

以下是代码段:

function MyCtrl($scope, $log, $timeout) {

  $scope.name = 'guy';
  $scope.guy = {};


  function myWatch() {
    return function(newValue, oldValue) {
      $log.info('these are the values', newValue, oldValue);

      if (newValue === oldValue) {
        $log.info('they are the same');
      } else {
        $log.info('they are different');
      }
    }
  }

  $scope.$watch('guy', myWatch(), true);

  $timeout(function() {
    $scope.guy = {
      'hello': 'world'
    };
  }, 3000, true);


}
<!DOCTYPE html>
<html ng-app>

<head>
  <script data-require="angular.js@1.2.16" data-semver="1.2.16" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="MyCtrl">
  <h1>Hello {{name}}!</h1>
</body>

</html>