我在ng-repeat中对数组进行过滤。
div.row(ng-repeat="log in logs | prepare_log | orderBy: 'log.created'")
在prepare_log过滤器中,我这样做:
value.stack_trace = angular.fromJson(value.stack_trace)
如果我将其更改为:
value.stack_trace = angular.fromJson(value.stack_trace).reverse()
我收到了infdig错误。
我不知道它是否相关,但我正在内部ng-repeat中迭代stack_trace属性。
我在这里做错了什么想法?
答案 0 :(得分:10)
由于您正在摘要循环期间更改模型,因此导致无限$ digest循环。
幕后发生的事情是:
ng-repeat解析集合表达式以确定哪些行需要“标记”出来并实例化观察者以在集合更改时收到通知
每次运行过滤器时,您都会通过为value.stack_trace
分配一个新值来更改其中一个项目,触发ng-repeat的观察者来重新选择并重新开始< / p>
Angular检测到循环并中止
要解决此问题,请避免更改过滤器中的模型。
希望有所帮助!
答案 1 :(得分:4)
因为角度将始终触发摘要一次以确保不再有更改。在每个摘要周期中,将调用prepare_log过滤器并返回一个值。如果返回值与最后一个值相同,则表示不再进行更改,应用程序状态稳定,因此angular不必触发额外的摘要。
但是在你的过滤器中,value.stack_trace将在每个摘要周期中反转,因此应用程序状态永远不会稳定,从而导致infdig(无限摘要)错误。
答案 2 :(得分:1)
解决由infdig
中的过滤器引起的ngRepeat
错误可能很麻烦且烦人。当您只想快速修复时,只要输入数组的顺序或大小没有变化,通常就足以表达,给我相同的结果。
如果您处理的模型都具有唯一的id
属性,这将变得更容易。
在这种情况下,我们希望部署一种通用的过滤器稳定方法:
angular
.module( "app" )
.factory( "stabilize", stabilizeFactory );
/**
* Generalization of a filter stabilization approach.
* As long as the input contains the same elements (identified by their `id`) and they are in the same order,
* the same result array is returned, thus preventing infdig errors.
*/
function stabilizeFactory() {
return function stabilize( filterFunc ) {
return function stableFilter() {
var array = arguments[ 0 ];
if( !array || !array.length ) {
return array;
}
var stabilizationId = idString( array );
if( array.$$stable ) {
if( array.$$stableId === stabilizationId ) {
return array.$$stable;
}
}
array.$$stable = filterFunc.apply( arguments );
array.$$stableId = stabilizationId;
return array.$$stable;
};
};
function idString( array ) {
return array.reduce( function appendKey( id, element ) {
return id + element.id;
}, "" );
}
}
要使用它,只需将您自己的过滤器功能包装在stabilize()
中,如下所示:
angular
.module( "app" )
.filter( "myFilter", myFilterProvider);
/** @ngInject */
function myFilterProvider( stabilize ) {
return stabilize( myFilter);
function myFilter( array ) {
if( !array || !array.length ) {
return array;
}
return array.filter( function( element ) {
return element.something === "foo";
}
);
}
}