Skip to content

Commit 07d5e42

Browse files
danieljancarpkozlowski-opensource
authored andcommitted
docs: revise documentation for @for control flow, 'track $index' performance issues explanation, and confusing 'trackBy' mention (angular#53806)
PR Close angular#53806
1 parent 0ddae16 commit 07d5e42

File tree

3 files changed

+108
-70
lines changed

3 files changed

+108
-70
lines changed

adev/src/content/guide/templates/control-flow.md

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,88 +2,104 @@
22

33
Angular templates support *control flow blocks* that let you conditionally show, hide, and repeat elements.
44

5-
IMPORTANT: Angular built-in control flow is in [developer preview](reference/releases#developer-preview). It is ready to try, but may change before becoming stable.
5+
IMPORTANT: Angular built-in control flow is in [developer preview](reference/releases#developer-preview). It is ready to
6+
try, but may change before becoming stable.
67

78
## `@if` block conditionals
89

910
The `@if` block conditionally displays its content when its condition expression is truthy:
1011

1112
```html
1213
@if (a > b) {
13-
{{a}} is greater than {{b}}
14+
{{a}} is greater than {{b}}
1415
}
1516
```
1617

17-
The `@if` block might have one or more associated `@else` blocks. Immediately after an `@if` block, you can optionally specify any number of `@else if` blocks and one `@else` block:
18+
The `@if` block might have one or more associated `@else` blocks. Immediately after an `@if` block, you can optionally
19+
specify any number of `@else if` blocks and one `@else` block:
1820

1921
```html
2022
@if (a > b) {
21-
{{a}} is greater than {{b}}
23+
{{a}} is greater than {{b}}
2224
} @else if (b > a) {
23-
{{a}} is less than {{b}}
25+
{{a}} is less than {{b}}
2426
} @else {
25-
{{a}} is equal to {{b}}
27+
{{a}} is equal to {{b}}
2628
}
2729
```
2830

2931
### Referencing the conditional expression's result
3032

31-
The new built-in `@if` conditional supports referencing of expression results to keep a solution for common coding patterns:
33+
The new built-in `@if` conditional supports referencing of expression results to keep a solution for common coding
34+
patterns:
3235

3336
```html
3437
@if (users$ | async; as users) {
35-
{{ users.length }}
38+
{{ users.length }}
3639
}
3740
```
3841

3942
## `@for` block - repeaters
4043

41-
The `@for` repeatedly renders content of a block for each item in a collection. The collection can be represented as any JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) but there are performance advantages of using a regular `Array`. A basic `@for` loop looks like:
44+
The `@for` repeatedly renders content of a block for each item in a collection. The collection can be represented as any
45+
JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) but there
46+
are performance advantages of using a regular `Array`. A basic `@for` loop looks like:
4247

4348
```html
4449
@for (item of items; track item.id) {
45-
{{ item.name }}
50+
{{ item.name }}
4651
}
4752
```
4853

4954
### `track` for calculating difference of two collections
5055

51-
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.
56+
The value of the `track` expression determines a key used to associate array items with the views in the DOM. Having
57+
clear indication of the item identity allows Angular to execute a minimal set of DOM operations as items are added,
58+
removed or moved in a collection.
5259

53-
Loops over immutable data without `trackBy` are one of the most common causes for performance issues across Angular applications. Because of the potential for poor performance, the `track` expression is required for the `@for` loops. When in doubt, using `track $index` is a good default.
60+
Using track effectively can significantly enhance your application's performance, especially in loops over data
61+
collections.
62+
63+
For collections that do not undergo modifications (no items are moved, added, or deleted), using `track $index` is an
64+
efficient strategy. For collections with mutable data or frequent changes, select a property that uniquely identifies
65+
each item to use as your track expression.
66+
67+
Be aware of the potential for increased DOM re-creation when using object identity as a track key with immutable data
68+
structures, as this can lead to unnecessary performance costs.
5469

5570
### `$index` and other contextual variables
5671

5772
Inside `@for` contents, several implicit variables are always available:
5873

59-
| Variable | Meaning |
60-
| -------- | ------- |
74+
| Variable | Meaning |
75+
|----------|-----------------------------------------------|
6176
| `$count` | Number of items in a collection iterated over |
62-
| `$index` | Index of the current row |
63-
| `$first` | Whether the current row is the first row |
64-
| `$last` | Whether the current row is the last row |
65-
| `$even` | Whether the current row index is even |
66-
| `$odd` | Whether the current row index is odd |
77+
| `$index` | Index of the current row |
78+
| `$first` | Whether the current row is the first row |
79+
| `$last` | Whether the current row is the last row |
80+
| `$even` | Whether the current row index is even |
81+
| `$odd` | Whether the current row index is odd |
6782

6883
These variables are always available with these names, but can be aliased via a `let` segment:
6984

7085
```html
7186
@for (item of items; track item.id; let idx = $index, e = $even) {
72-
Item #{{ idx }}: {{ item.name }}
87+
Item #{{ idx }}: {{ item.name }}
7388
}
7489
```
7590

7691
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable names could collide.
7792

7893
### `empty` block
7994

80-
You can optionally include an `@empty` section immediately after the `@for` block content. The content of the `@empty` block displays when there are no items:
95+
You can optionally include an `@empty` section immediately after the `@for` block content. The content of the `@empty`
96+
block displays when there are no items:
8197

8298
```html
8399
@for (item of items; track item.name) {
84-
<li> {{ item.name }} </li>
100+
<li> {{ item.name }}</li>
85101
} @empty {
86-
<li> There are no items. </li>
102+
<li> There are no items.</li>
87103
}
88104
```
89105

@@ -93,23 +109,24 @@ The syntax for `switch` is very similar to `if`, and is inspired by the JavaScri
93109

94110
```html
95111
@switch (condition) {
96-
@case (caseA) {
97-
Case A.
98-
}
99-
@case (caseB) {
100-
Case B.
101-
}
102-
@default {
103-
Default case.
104-
}
112+
@case (caseA) {
113+
Case A.
114+
}
115+
@case (caseB) {
116+
Case B.
117+
}
118+
@default {
119+
Default case.
120+
}
105121
}
106122
```
107123

108124
The value of the conditional expression is compared to the case expression using the `===` operator.
109125

110126
**`@switch` does not have fallthrough**, so you do not need an equivalent to a `break` or `return` statement.
111127

112-
The `@default` block is optional and can be omitted. If no `@case` matches the expression and there is no `@default` block, nothing is shown.
128+
The `@default` block is optional and can be omitted. If no `@case` matches the expression and there is no `@default`
129+
block, nothing is shown.
113130

114131
## Built-in control flow and the `NgIf`, `NgSwitch` and `NgFor` structural directives
115132

@@ -120,16 +137,21 @@ The `@switch` block replaces `ngSwitch` with major benefits:
120137
* it does not require a container element to hold the condition expression or each conditional template;
121138
* it supports template type-checking, including type narrowing within each branch.
122139

123-
The `@for` block replaces `*ngFor` for iteration, and has several differences compared to its structural directive `NgFor` predecessor:
140+
The `@for` block replaces `*ngFor` for iteration, and has several differences compared to its structural
141+
directive `NgFor` predecessor:
124142

125-
* tracking expression (calculating keys corresponding to object identities) is mandatory but has better ergonomics (it is enough to write an expression instead of creating the `trackBy` method);
126-
* uses a new optimized algorithm for calculating a minimal number of DOM operations to be performed in response to changes in a collection, instead of Angular’s customizable diffing implementation (`IterableDiffer`);
143+
* tracking expression (calculating keys corresponding to object identities) is mandatory but has better ergonomics (it
144+
is enough to write an expression instead of creating the `trackBy` method);
145+
* uses a new optimized algorithm for calculating a minimal number of DOM operations to be performed in response to
146+
changes in a collection, instead of Angular’s customizable diffing implementation (`IterableDiffer`);
127147
* has support for `@empty` blocks.
128148

129-
The `track` setting replaces `NgFor`'s concept of a `trackBy` function. Because `@for` is built-in, we can provide a better experience than passing a `trackBy` function, and directly use an expression representing the key instead. Migrating from `trackBy` to `track` is possible by invoking the `trackBy` function:
149+
The `track` setting replaces `NgFor`'s concept of a `trackBy` function. Because `@for` is built-in, we can provide a
150+
better experience than passing a `trackBy` function, and directly use an expression representing the key instead.
151+
Migrating from `trackBy` to `track` is possible by invoking the `trackBy` function:
130152

131153
```html
132154
@for (item of items; track itemId($index, item)) {
133-
{{ item.name }}
155+
{{ item.name }}
134156
}
135157
```

aio/content/blocks/core/for.md

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,55 @@ The `@for` block repeatedly renders content of a block for each item in a collec
44

55
```html
66
@for (item of items; track item.name) {
7-
<li> {{ item.name }} </li>
7+
<li>{{ item.name }}</li>
88
} @empty {
9-
<li> There are no items. </li>
9+
<li>There are no items.</li>
1010
}
1111
```
1212

1313
@description
1414

15-
The `@for` block renders its content in response to changes in a collection. Collections can be any JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols), but there are performance advantages of using a regular `Array`.
15+
The `@for` block renders its content in response to changes in a collection. Collections can be any
16+
JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols),
17+
but there are performance advantages of using a regular `Array`.
1618

17-
You can optionally include an `@empty` section immediately after the `@for` block content. The content of the `@empty` block displays when there are no items.
19+
You can optionally include an `@empty` section immediately after the `@for` block content. The
20+
content of the `@empty` block displays when there are no items.
1821

1922
<h3> track and objects identity </h3>
2023

21-
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.
24+
The value of the `track` expression determines a key used to associate array items with the views in
25+
the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM
26+
operations as items are added, removed or moved in a collection.
2227

23-
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, the `track` expression is required for the `@for` loops. When in doubt, using `track $index` is a good default.
28+
To optimize performance, especially in loops over immutable data, ensure the track expression is effectively used to
29+
identify each item uniquely. Because of the potential for poor performance, the `track` expression
30+
is required for the `@for` loops.
31+
32+
For collections that remain static , `track $index` provides a straightforward tracking mechanism. For dynamic
33+
collections experiencing additions, deletions, or reordering, opt for a
34+
unique property of each item as the tracking key.
2435

2536
<h3> `$index` and other contextual variables </h3>
2637

27-
Inside `@for` contents, several implicit variables are always available:
38+
Inside `@for` contents, several implicit variables are always available:
2839

29-
| Variable | Meaning |
30-
| -------- | ------- |
40+
| Variable | Meaning |
41+
|----------|-----------------------------------------------|
3142
| `$count` | Number of items in a collection iterated over |
32-
| `$index` | Index of the current row |
33-
| `$first` | Whether the current row is the first row |
34-
| `$last` | Whether the current row is the last row |
35-
| `$even` | Whether the current row index is even |
36-
| `$odd` | Whether the current row index is odd |
43+
| `$index` | Index of the current row |
44+
| `$first` | Whether the current row is the first row |
45+
| `$last` | Whether the current row is the last row |
46+
| `$even` | Whether the current row index is even |
47+
| `$odd` | Whether the current row index is odd |
3748

3849
These variables are always available with these names, but can be aliased via a `let` segment:
3950

4051
```html
4152
@for (item of items; track item.id; let idx = $index, e = $even) {
42-
Item #{{ idx }}: {{ item.name }}
53+
Item #{{ idx }}: {{ item.name }}
4354
}
4455
```
4556

46-
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable names could collide.
57+
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable
58+
names could collide.

tools/manual_api_docs/blocks/for.md

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
The `@for` block repeatedly renders content of a block for each item in a collection.
22

3-
## Syntax
3+
@syntax
44

55
```html
66
@for (item of items; track item.name) {
7-
<li> {{ item.name }} </li>
7+
<li>{{ item.name }}</li>
88
} @empty {
9-
<li> There are no items. </li>
9+
<li>There are no items.</li>
1010
}
1111
```
1212

13-
## Description
13+
@description
1414

1515
The `@for` block renders its content in response to changes in a collection. Collections can be any
1616
JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols),
@@ -25,28 +25,32 @@ The value of the `track` expression determines a key used to associate array ite
2525
the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM
2626
operations as items are added, removed or moved in a collection.
2727

28-
Loops over immutable data without `trackBy` as one of the most common causes for performance issues
29-
across Angular applications. Because of the potential for poor performance, the `track` expression
30-
is required for the `@for` loops. When in doubt, using `track $index` is a good default.
28+
To optimize performance, especially in loops over immutable data, ensure the track expression is effectively used to
29+
identify each item uniquely. Because of the potential for poor performance, the `track` expression
30+
is required for the `@for` loops.
31+
32+
For collections that remain static , `track $index` provides a straightforward tracking mechanism. For dynamic
33+
collections experiencing additions, deletions, or reordering, opt for a
34+
unique property of each item as the tracking key.
3135

3236
<h3> `$index` and other contextual variables </h3>
3337

34-
Inside `@for` contents, several implicit variables are always available:
38+
Inside `@for` contents, several implicit variables are always available:
3539

36-
| Variable | Meaning |
37-
| -------- | ------- |
40+
| Variable | Meaning |
41+
|----------|-----------------------------------------------|
3842
| `$count` | Number of items in a collection iterated over |
39-
| `$index` | Index of the current row |
40-
| `$first` | Whether the current row is the first row |
41-
| `$last` | Whether the current row is the last row |
42-
| `$even` | Whether the current row index is even |
43-
| `$odd` | Whether the current row index is odd |
43+
| `$index` | Index of the current row |
44+
| `$first` | Whether the current row is the first row |
45+
| `$last` | Whether the current row is the last row |
46+
| `$even` | Whether the current row index is even |
47+
| `$odd` | Whether the current row index is odd |
4448

4549
These variables are always available with these names, but can be aliased via a `let` segment:
4650

4751
```html
4852
@for (item of items; track item.id; let idx = $index, e = $even) {
49-
Item #{{ idx }}: {{ item.name }}
53+
Item #{{ idx }}: {{ item.name }}
5054
}
5155
```
5256

0 commit comments

Comments
 (0)