$ watch中的set变量有时会失败?

apn*_*ing 5 angularjs angularjs-directive

使用Angular 1.0.7:

我有一个指令,用于显示样式复选框.

请看这里的plunkr.

有时(并非总是)我的观察者不会更新我的范围变量之一:

这是一个失败的序列:

  • FOO
  • 酒吧
  • 所有
  • FOO
  • 酒吧

在此输入图像描述

我想知道为什么更新不会发生.

Gm0*_*m0t 2

这是一个非常有趣的问题,因此您单击的处理程序和偏好设置的组合存在问题。电子邮件手表:

角度js代码:

//https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js line 4510
scope.$watch(function parentValueWatch() {
    var parentValue = parentGet(parentScope);

    if (parentValue !== scope[scopeName]) {
        // we are out of sync and need to copy
        if (parentValue !== lastValue) {
            // parent changed and it has precedence
            lastValue = scope[scopeName] = parentValue;
        } else {
            // if the parent can be assigned then do so
            parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
        }
    }
    return parentValue;
});
break;
Run Code Online (Sandbox Code Playgroud)

您从单击foo + bar开始,我们有:

all: true
foo: true
bar: true
Run Code Online (Sandbox Code Playgroud)

单击切换全部

//by this code
var new_val = toggled_input_value();
$scope.model = new_val;
Run Code Online (Sandbox Code Playgroud)

$scope.model 是上面代码中的scope[scopeName] ,因此scope[scopeName] = false 且lastValue = true,parentValue = true(它们将在$digest 运行后更改)

$scope.clicked({ value: new_val });
Run Code Online (Sandbox Code Playgroud)

将会通知

$scope.toggleAll = function(new_value){
  if (new_value){
    $scope.preferences.email.foo = true;
    $scope.preferences.email.bar = true;
  }
  else{
    $scope.preferences.email.foo = false;
    $scope.preferences.email.bar = false;    
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,

all: true - $digest have not been run
foo: false
bar: false
Run Code Online (Sandbox Code Playgroud)

并且,开始 $digest... 第一个调用将是:

$scope.$watch('preferences.email', function(new_value){
  var bool = new_value.foo && new_value.bar;
  $scope.preferences.all = bool;
}, true);
Run Code Online (Sandbox Code Playgroud)

所以,

all: false
foo: false
bar: false
Run Code Online (Sandbox Code Playgroud)

这是一个问题,因为在下一个parentValueWatch调用中我们会得到:

parentValue = false //$scope.preferences.all
scope[scopeName] = false //$scope.model
lastValue = true
Run Code Online (Sandbox Code Playgroud)

所以,parentValue ===scope[scopeName]和lastValue尚未更新......这是一个错误:)

当你将 $scope.preferences.all 更改为 true 时,你会得到

$scope.preferences.all === lastValue //true
Run Code Online (Sandbox Code Playgroud)

并打电话

// if the parent can be assigned then do so
parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
Run Code Online (Sandbox Code Playgroud)

因此, $scope.preferences.all 将变为 false,而不是 true

你可以在这里查看http://plnkr.co/edit/YEHqA101YwWKDvK6odFf?p=preview (console.trace)