ng-repeat 中的函数调用了 4 次 (AngularJs)

function inside ng-repeat called 4 times (AngularJs)

以下 HTML 代码用 21 phones 填充 ul:

<li ng-repeat="phone in phones" ng-class="{'digestTest': countDigestOccurences(phone) }">
  <p>{{phone.snippet}}</p>
</li>

countDigestOccurences 是一种 JavaScript 方法,它使用字典来跟踪每个 phone.

调用了多少次 countDigestOccurences()
$scope.countDigestOccurences = function(phone){
  var phoneFound = false;     
  $.each($scope.digestOccurencesPerPhone, function(){
      if(this.phone.id == phone.id){
        phoneFound = true;
        this.occurences++;
      }
  });

  if(!phoneFound)
  { 
    $scope.digestOccurencesPerPhone.push({
      phone: phone,
      occurences: 1
    });
  }
}

通过这个方法我可以清楚地看到每次 phone countDigestOccurences 被调用 4 次。 我一辈子都弄不明白为什么它被调用了 4 次。

更新:

即使Phone项的HTML如下,循环次数仍为4:

    <li ng-repeat="phone in phones "
        class="thumbnail phone-listing" ng-class="{ 'digestTest': countDigestOccurences(phone),  'digestTestAgain': randomMethodDoesNothing() }">
      <p>{{phone.snippet}}</p>
    </li>

您通过 $http 接到了多少 ajax 次电话?他们每个人都会触发一个 $digest。此外,如果有什么变化(并且已经发生,新数据到达),另一个 $digest 将 运行 确保它涵盖所有内容。

为避免这种情况,在父元素的 ng-if 上添加一个布尔值,并在所有 ajax 调用到达后将其设置为真(参见 $q)。

当 Angular 编译并在视图上看到一个表达式时,如 ng-class="function()"ng-model="toto",会为其创建一个 $watch。在每个摘要周期中,手表都会通过脏检查进行评估,以确定模型是否有任何变化。

所以在你的 ng-repeat 中,你有:phones 集合上的一名观察者,每个 phone 实例上的一名观察者和函数上的一名观察者。由于视图上的函数不是范围变量,angular 无法知道函数的结果是否已更改(您可能会影响函数中的其他范围变量)因此,它会重新评估函数结果对于每个摘要周期。

所以你有 phones + phone + 函数 + 最后一个摘要周期来验证一切正常:4 个周期

除非极少数情况,否则最好不要在视图中使用函数。相反,将函数的结果存储在范围变量中并在视图中呈现该变量。

更新:

由于下面的讨论,请注意只有一个手表是为 ng-class 指令创建的,它对应于 ng-class 的值。即,与: ng-class="{'toto' : functionOne(), 'titi' : functionTwo()}",手表已开启:{'toto' : functionOne(), 'titi' : functionTwo()}。 从AngularJs发出的指令代码:scope.$watch(attr[name], ngClassWatchAction, true);