$ rootScope:过滤器引起的infdig错误?

时间:2014-01-07 03:35:59

标签: angularjs

我在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属性。

我在这里做错了什么想法?

3 个答案:

答案 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";
            }
        );
    }
}