$ rootScope: infdig error caused by filter?

I am doing a filter in an array in ng-repeat.

div.row(ng-repeat="log in logs | prepare_log | orderBy: 'log.created'") 

In the prepare_log filter, I do this:

 value.stack_trace = angular.fromJson(value.stack_trace) 

If I changed it to this:

 value.stack_trace = angular.fromJson(value.stack_trace).reverse() 

I get an infdig error.

I don't know if this matches, but I am repeating the stack_trace property in an internal ng repeat.

Any ideas what I'm doing wrong here?

+7
angularjs
source share
3 answers

You invoke the infinite $ digest loop because you are changing the model during the digest loop.

What happens behind the scenes:

  • ng-repeat parses the expression of the collection to find out which lines to print, and creates an observer instance to be notified when the collection changes

  • every time a filter is executed, you change one of the elements by assigning a new value to value.stack_trace , calling the ng-repeat observer to pick it up and start over and over

  • Angular detects a loop and aborts

To solve the problem, do not modify the model in your filter.

Hope this helps!

+10
source share

because angular will always invoke the assembly again to make sure there are no more changes. in each digest cycle, the prepare_log filter will be called and return a value. if the return value matches the previous one, this means that there are more changes and the application state is not stabilizing, so angular should not start an additional digest.

but in your filter, the value of value.stack_trace will be canceled in each digest cycle, so the state of the application will never stabilize, which causes an infdig (infinite digest) error.

+4
source share

Solving infdig errors caused by filters in ngRepeat can be cumbersome and annoying. When you just want a quick fix, it is often enough to formulate , until the input array changes in order or size, give me the same result .

This is much simpler if the models you deal with all have a unique id property.

In this case, we like to deploy a general approach to filter stabilization:

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

To use this, simply wrap your own filter function in stabilize() , for example:

 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"; } ); } } 
+1
source share

All Articles