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);
以下 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);