It appears that I am still struggling to grasp the mechanism behind ng-repeat
, $$hashKeys
, and track by
.
Currently, in my project, I am working with AngularJS 1.6.
The Issue:
I have an array of complex objects that I want to display as a list in my view. However, before rendering them, I need to modify these objects by mapping or enhancing them:
const sourceArray = [{id: 1, name: 'Dave'}, {id:2, name: Steve}]
const persons = sourceArray.map((e) => ({enhancedName: e.name + e.id}))
//The content of persons becomes:
//[{enhancedName: 'Dave_1'}, {enhancedName: 'Steve_2'}]
Binding this to the view should work like this:
<div ng-repeat="person in ctrl.getPersons()">
{{person.enhancedName}}
</div>
However, this leads to a $digest()
-loop because .map
creates new object instances each time it is called. As I bind this to ng-repeat via a function, it gets reevaluated in every $digest
cycle, preventing the model from stabilizing and causing Angular to run additional cycles due to the objects being marked as $dirty
.
Confusion:
This issue is not new, and there are various solutions available:
In an Angular issue from 2012, Igor Minar suggested manually setting the $$hashKey property to indicate that the generated objects are the same. Despite his successful fiddle example, even simple implementations led to a $digest
loop in my project. I attempted upgrading the Angular version in the fiddle which resulted in a crash.
Since Angular 1.3, we have track by
for addressing this specific problem. However, both:
<div ng-repeat="person in ctrl.getPersons() track by $index">
and
<div ng-repeat="person in ctrl.getPersons() track by person.enhancedName">
resulted in a $digest
loop. I believed that the track by
statement would inform Angular that it works with the same objects, but it seems that it continuously checks for changes. At this point, I am unsure how to effectively debug this issue.
Question:
Is it feasible to use a filtered/modified array as a data source for ng-repeat
?
I prefer not to store the modified array on my controller as I require constant updates to its data. Having to manually maintain and refresh it in the controller rather than relying on databinding is something I wish to avoid.