Angular 17 introduced a new control flow syntax moving from
<div *ngFor="let item of items"></div>
to
@for (item of items) {
<div></div>
}
When directly translating my loops, I get the following error:
NG5002: @for loop must have a "track" expression
Angular 17 introduced a new control flow syntax moving from
<div *ngFor="let item of items"></div>
to
@for (item of items) {
<div></div>
}
When directly translating my loops, I get the following error:
NG5002: @for loop must have a "track" expression
Share
Improve this question
asked Nov 8, 2023 at 15:54
kacasekacase
2,8692 gold badges24 silver badges32 bronze badges
3
- Feature, not a bug – Andrew Allen Commented Nov 8, 2023 at 15:57
- 1 @AndrewAllen Yes a very cool feature as well. Still something many might not be aware of when migrating. So I deemed it helpful to post. – kacase Commented Nov 8, 2023 at 16:05
- Here is the official documentaion with the playground: angular.dev/tutorials/learn-angular/5-control-flow-for – Hansana Prabath Commented Sep 13, 2024 at 16:13
1 Answer
Reset to default 36Background
As part of the new control flow structure introduced in angular v17 the track
expression needs to be defined.
Track is used to keep track of items in an array and their association to the DOM.
From the Angular documentation:
The value of the
track
expression determines a key used to associate array items with the views in the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM operations as items are added, removed or moved in a collection.
Loops over immutable data without
trackBy
as one of the most common causes for performance issues across Angular applications. Because of the potential for poor performance, thetrack
expression is required for the@for
loops. When in doubt, usingtrack $index
is a good default.
From :https://angular.dev/guide/templates/control-flow#track-for-calculating-difference-of-two-collections
Solutions
Use a property of the element
If the elements in your array have any kind of property attached to them that allows identifying them you can use it for the tracking. Any kind of ID works great.
let items = [
{ id: "id1", content: []},
{ id: "id2", content: []},
]
@for (item of items; track item.id) {
<div></div>
}
Use track $index
This uses the index of the current row to associate the row with the element in the DOM. This can be used as default, if no better property is available and the array itself is immutable.
@for (item of items; track $index) {
<div></div>
}
$index
will be recalculated if an item is added to the array, so it could lead to some unexpected behaviour or performance issues, and should not be used if a unique identifier is available.