在指令中调用$ setViewValue不会在控制器中触发$ watch

时间:2014-08-08 10:32:54

标签: javascript angularjs angularjs-directive digest angular-ngmodel

我正在使用带有像这样的

的ngModelController的指令
  var directive = {
    link: link,
    restrict: 'E',
    require: '?ngModel'
  }

我的链接功能做了这样的事情(我省略了长指令的东西)

function link(scope, element, attrs, ctrl) {

  scope.updateModel = function(){
    var newModel = {};
    newModel.aValue = 'foo';
    ctrl.$setViewValue(newModel);
  }

}

我在我的控制器中使用该指令

查看:此内容已正确更新

<my-directive ng-model="aModel">
  {{aModel.aValue}} // This is changed correctly when I update the value in the directive
</my-directive>

控制器:这是我遇到问题的地方

$scope.aModel = {};
$scope.aModel.aValue = 'bar';

$scope.$watch('aModel', function(newValue, oldValue){
    console.log('aModel changed'); // This is never fired
});

$scope.$watch('aModel.aValue', function(newValue, oldValue){
    console.log('aModel changed'); // This is neither fired
});

$setViewValue的文档说

  

“请注意,调用此函数不会触发$ digest。”

因此我尝试使用$render$digest$apply手动触发,但每次都遇到麻烦,因为控制台说$digest is already in progress
那有什么问题呢?

更新

我刚刚意识到一些非常有趣的事情 添加$timeout来检查控制器中的值,我意识到它实际上没有被改变,这可能是为什么$ watch函数没有被调用的原因。 但是由于视图已更新,我并不是真的明白了。

情况就是这样:

控制器

$timeout(function(){
  console.log('Check aModel value in the controller');
  console.log($scope.aModel.aValue); // This is always 'bar' even if the view display 'foo'
},10000);

更新2

我认为我发现了问题:ngModel不能是一个对象,但它必须是一个值 我打开这个问题,看看是否有人提供了不同的解决方案,但我想这就是重点。

更新3
我错了,您可以将ngModel更新为对象,但无法触发$ watch方法 我创建了a plunker to show the problem 我提出了一个大的超时,以避免任何$ digest正在进行中的问题 任何提示都会非常感激。

2 个答案:

答案 0 :(得分:0)

将第三个参数true添加到$watch函数。

答案 1 :(得分:0)

使用$ timeout且没有时间参数来调用$ apply并触发摘要循环。这将导致它稍后执行一小部分而不会在摘要循环错误中进入摘要循环。很明显,你所做的不是“有角度意识的”。所以你需要使用$ apply触发摘要循环,但是你需要在摘要循环中触发,所以你需要使用&#39; hack&#39;如上所述。