In a directive, I am using ngRepeat
that gets its items from a parametrized function on the scope.
In a simplified manner, it looks like this:
<div data-ng-repeat="data in containerItems">
<div data-ng-repeat="myItem in getItems(data) track by myItem.Id">
<!-- some content -->
</div>
</div>
My problem is that I cannot seem to get rid of the following exception:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
As far as I could figure out based upon several other questions (such as this, or this), ngRepeat
appears to think the items are updated each time it re-requests them, causing it prompt yet another digest cycle, eventually ending up with too many consecutive of them and giving up.
In particular, one comment by user g00fy was insightful to me: Indeed, I am using lodash's _.map
function to generate the list of items displayed by ngRepeat
, thus creating new object instances each time ngRepeat
re-requests its items.
At first, I thought I could solve this by saving the return value of my item generation function into a variable on the scope. This did away with the above error.
Unfortunately, it is not a suitable solution for me, as the scope is shared by several instances of my directive within which ngRepeat
is used. I really need each ngRepeat
retrieve the items from the generation function with the appropriate parameter.
At first, I was using
track by $index
but I have also tried something like
track by myItem.Id
I had hoped that this would force ngRepeat
to assume the item was changed only when an ID changes. However, none of this seems to prevent the above exception from happening.
Is there any way I can force AngularJS to only consider an item in ngRepeat
changed when its values have changed, rather than the instance?
Structurally, it seems like the return value of getItems(data)
could be saved on data
. However, code in the framework of the application I am working on (which means it is relied upon to behave as it does by many modules of the application and must not be changed) will directly take the object graph that contains data
and send that to the server-side backend. Hence, data
is not the right place for computed runtime data.
To provide a more complete example, the getItems
function looks roughly like this:
$scope.getItems = function (data) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
return itemSet.customItems.slice(1);
} else {
return _.map(standardItems.slice(1), function (si) {
return {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
});
}
};
The specifics here are not relevant. The important part is that I retrieve the items from elsewhere depending on something in the parameter data
, and then the items may be in a format that requires transformation into a canonical format that is processed by my ngRepeat
-ed template.