Skip to content

Commit 3433728

Browse files
pkozlowski-opensourcedylhunn
authored andcommitted
docs: guide for the built-in control flow (angular#52369)
This change adds a dedicated developer guide for the built-in control flow. PR Close angular#52369
1 parent df86e37 commit 3433728

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

.pullapprove.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ groups:
342342
'aio/content/blocks/**/{*,.*}',
343343
'aio/content/guide/hydration.md',
344344
'aio/content/guide/signals.md',
345+
'aio/content/guide/control_flow.md',
345346
'aio/content/examples/injection-token/**/{*,.*}',
346347
])
347348
reviewers:

aio/content/guide/control_flow.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Built-in control flow
2+
3+
Angular templates support *control flow blocks* that let you conditionally show, hide, and repeat elements.
4+
5+
<div class="alert is-important">
6+
7+
Angular built-in control flow is in [developer preview](/guide/releases#developer-preview). It is ready to try, but may change before becoming stable.
8+
9+
</div>
10+
11+
## `@if` block conditionals
12+
13+
The `@if` block conditionally displays its content when its condition expression is truthy:
14+
15+
```html
16+
@if (a > b) {
17+
{{a}} is greater than {{b}}
18+
}
19+
```
20+
21+
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:
22+
23+
```html
24+
@if (a > b) {
25+
{{a}} is greater than {{b}}
26+
} @else if (b > a) {
27+
{{a}} is less than {{b}}
28+
} @else {
29+
{{a}} is equal to {{b}}
30+
}
31+
```
32+
33+
### Referencing the conditional expression's result
34+
35+
The new built-in `@if` conditional supports referencing of expression results to keep a solution for common coding patterns:
36+
37+
```html
38+
@if (users$ | async; as users) {
39+
{{ users.length }}
40+
}
41+
```
42+
43+
## `@for` block - repeaters
44+
45+
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:
46+
47+
```html
48+
@for (item of items; track item.id) {
49+
{{ item.name }}
50+
}
51+
```
52+
53+
### `track` for calculating difference of two collections
54+
55+
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+
57+
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.
58+
59+
### `$index` and other contextual variables
60+
61+
Inside `@for` contents, several implicit variables are always available:
62+
63+
| Variable | Meaning |
64+
| -------- | ------- |
65+
| `$count` | Number of items in a collection iterated over |
66+
| `$index` | Index of the current row |
67+
| `$first` | Whether the current row is the first row |
68+
| `$last` | Whether the current row is the last row |
69+
| `$even` | Whether the current row index is even |
70+
| `$odd` | Whether the current row index is odd |
71+
72+
These variables are always available with these names, but can be aliased via a `let` segment:
73+
74+
```html
75+
@for (item of items; track item.id; let idx = $index, e = $even) {
76+
Item #{{ idx }}: {{ item.name }}
77+
}
78+
```
79+
80+
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable names could collide.
81+
82+
### `empty` block
83+
84+
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:
85+
86+
```html
87+
@for (item of items; track item.name) {
88+
<li> {{ item.name }} </li>
89+
} @empty {
90+
<li> There are no items. </li>
91+
}
92+
```
93+
94+
## `@switch` block - selection
95+
96+
The syntax for `switch` is very similar to `if`, and is inspired by the JavaScript `switch` statement:
97+
98+
```html
99+
@switch (condition) {
100+
@case (caseA) {
101+
Case A.
102+
}
103+
@case (caseB) {
104+
Case B.
105+
}
106+
@default {
107+
Default case.
108+
}
109+
}
110+
```
111+
112+
The value of the conditional expression is compared to the case expression using the `===` operator.
113+
114+
**`@switch` does not have fallthrough**, so you do not need an equivalent to a `break` or `return` statement.
115+
116+
The `@default` block is optional and can be omitted. If no `@case` matches the expression and there is no `@default` block, nothing is shown.
117+
118+
## Built-in control flow and the `NgIf`, `NgSwitch` and `NgFor` structural directives
119+
120+
The `@if` block replaces `*ngIf` for expressing conditional parts of the UI.
121+
122+
The `@switch` block replaces `ngSwitch` with major benefits:
123+
* it does not require a container element to hold the condition expression or each conditional template;
124+
* it supports template type-checking, including type narrowing within each branch.
125+
126+
The `@for` block replaces `*ngFor` for iteration, and has several differences compared to its structural directive `NgFor` predecessor:
127+
* tracking expression (calculating keys corresponding to object identities) is mandatory but has better ergonomic (it is enough to write an expression instead of creating the `trackBy` method);
128+
* 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`);
129+
* has support for `@empty` blocks.
130+
131+
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:
132+
133+
```html
134+
@for (item of items; track itemId($index, item)) {
135+
{{ item.name }}
136+
}
137+
```

aio/content/navigation.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,11 @@
772772
"title": "Feature preview",
773773
"tooltip": "Angular preview features and APIs",
774774
"children": [
775+
{
776+
"url": "guide/control_flow",
777+
"title": "Built-in control flow",
778+
"tooltip": "Angular built-in control flow: if, for and switch"
779+
},
775780
{
776781
"url": "guide/signals",
777782
"title": "Signals",

0 commit comments

Comments
 (0)