Agat
Agat

Reputation: 358

Angular ng-repeat - creating collection dynamically

The problem occurs when trying to ng-repeat over dynamically created collection: Angular is going in to loop with 10 $digest() iterations reached. Aborting! error

I have simplified the problem to minimum with this example

<body ng-init='a = [1, 2, 3]'>
    <div ng-repeat="item in a.reverse()">{{item}}</div>
</body>

and here is it working copy in Plunkr (View shows correct result, but in console you will see errors mentioned above. More complicated examples fail completely)

Considered [1, 2, 3] could be array of objects, if it may make any difference

So questions are why is it so, and is there an easy way to come over this?

Thanks

Upvotes: 3

Views: 859

Answers (4)

Kareem Elshahawy
Kareem Elshahawy

Reputation: 1421

The problem is that you're calling the reverse function in ng-repeat and that $apply and $digest many times. If you're using AngularJS 1.3.x and your data will be created once and will not change at run-time, you can use bind-once property by typing the following in any of ng-(directives)

<body ng-init='a = [1, 2, 3].reverse()'>
   <div ng-repeat="item in ::a">{{item}}</div> 
</body>

prefixing a with :: tells AngularJS that this array or this variable won't be changed, so it will release the $watch function from it and won't consume $digest too many times.

For more information about bind once feature, check this one-time-binding

For the reversing technique itself if it's dynamically created and frequently changed, you can use one of the following approaches:

<body ng-init='a = [1, 2, 3]'>
  <div ng-repeat="item in a.slice().reverse()">{{item}}</div>
</body>

or also you can wrap this into filter, you can use it as follows:

app.filter('reverse', function() {
  return function(items) {
    return items.slice().reverse();
  };
});

and in the HTML type the following line of code:

<body ng-init='a = [1, 2, 3]'>
  <div ng-repeat="item in a | reverse">{{item}}</div>
</body>

for ordering array of objects in general, you should use the following:

<body ng-init='a = [{id: 1}, {id: 2}, {id: 3}]'>
  <div ng-repeat="item in a | orderBy:'id':true">{{item.id}}</div>
</body>

using true for reverse ordering and false for ascending ordering.

You can check also this question and answer for more information: angular ng-repeat in reverse

Upvotes: 5

selami
selami

Reputation: 1

using a function for ng-repeat is not a prefer way, you have to be carefully when using function for ng-repeat items. please check this post.

How to Loop through items returned by a function with ng-repeat?

Upvotes: 0

Nicola Ferraro
Nicola Ferraro

Reputation: 4189

This happens because angular uses a fixed-point model for rendering the objects in the page. When, after applying one iteration, all the "digest" of the objects do not change, the model is considered stable and it is rendered in the view. If the model is not stable after x=10 iterations, then an error is raised. In your case, the function reverse() generate always a new model object with a different digest.

For your particular problem, you can use ng-repeat with the orderBy clause (assuming that the model object is an array).

In general, when you have a main model and many derived sub-models, it is good practice to derive the sub-models using $watch expressions in a "reactive" fashion.

Upvotes: 1

rmuller
rmuller

Reputation: 1837

It is because of you calling the reverse() function in the ng-repeat.

Like this it works without errors

<body ng-init='a = [1, 2, 3].reverse()'>
   <div ng-repeat="item in a">{{item}}</div> 
</body>

Upvotes: 2

Related Questions