为什么我的Angular.js控制器在以下代码中执行两次函数?

时间:2014-06-27 19:11:42

标签: javascript angularjs controller

我有一个ng-repeat循环遍历属于SomeController的对象数组:

<div ng-controller="SomeController as aCtrl">
  <div ng-repeat="category in aCtrl.categories">
    <p ng-show="aCtrl.checkShouldBeDisplayed(category)">{{category.name}}</p>
  </div>
</div>

控制器定义为:

app.controller('SomeController', function() {

this.categories = [{
  "name": "one",
}, {
  "name": "two",
}, {
  "name": "three",
}, {
  "name": "four",
}];

this.counter = 0;

this.checkShouldBeDisplayed = function(channel) {
  this.counter = this.counter + 1;
  console.log("executing checkShouldBeDisplayed " + this.counter);
  return true;
};

}); 

我希望checkShouldBeDisplayed函数计为4,因为SomeController.categories数组中有四个元素。相反,它计为8 - 在此处检查:http://plnkr.co/edit/dyvM49kLLTGof9O92jGb(您需要在浏览器中查看控制台以查看日志)。我怎样才能绕过这种行为?干杯!

2 个答案:

答案 0 :(得分:3)

这是预期的;指令ng-repeat将重复次数,因为框架认为是正确的;这称为脏检查,您可以在this post中阅读更多相关内容。

出于这个原因,最好是以声明的方式而不是强制性地思考。换句话说,方法checkShouldBeDisplayed应该只执行它在锡上所说的内容,而不是依赖于调用它的次数。如果您需要执行某种聚合或操作,则应在控制器的其他位置执行。

答案 1 :(得分:1)

根据 the docs

  

每次调用$ digest()时都会调用watchExpression,并应返回将要监视的值。 (由于$ digest()在检测到更改时重新运行,因此watchExpression可以每$ digest()执行多次,并且应该是幂等的。)
  [...]
  监听器可能会更改模型,这可能会触发其他侦听器触发。这是通过重新运行观察者直到没有检测到任何变化来实现的。

所有ngShow都会注册观察者:

scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
});

你的函数是ngShow的watch-expression,因此被执行两次:
1.在第一个$摘要中,它检测到新值 2.在第二个$摘要中,它验证没有任何变化并终止。


在此 short demo 中,您可以验证有两个$ digest循环。