In-depth Guides
Templates

Control flow

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

Note: This was previously accomplished with the *ngIf, *ngFor, and *ngSwitch directives.

Conditionally display content with @if, @else-if and @else

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

      
@if (a > b) {  <p>{{a}} is greater than {{b}}</p>}

If you want to display alternative content, you can do so by providing any number of @else if blocks and a singular @else block.

      
@if (a > b) {  {{a}} is greater than {{b}}} @else if (b > a) {  {{a}} is less than {{b}}} @else {  {{a}} is equal to {{b}}}

Referencing the conditional expression's result

The @if conditional supports saving the result of the conditional expression into a variable for reuse inside of the block.

      
@if (user.profile.settings.startDate; as startDate) {  {{ startDate }}}

This can be useful for referencing longer expressions that would be easier to read and maintain within the template.

Repeat content with the @for block

The @for block loops through a collection and repeatedly renders the content of a block. The collection can be any JavaScript iterable, but Angular has additional performance optimizations for Array values.

A typical @for loop looks like:

      
@for (item of items; track item.id) {  {{ item.name }}}

Why is track in @for blocks important?

The track expression allows Angular to maintain a relationship between your data and the DOM nodes on the page. This allows Angular to optimize performance by executing the minimum necessary DOM operations when the data changes.

Using track effectively can significantly improve your application's rendering performance when looping over data collections.

Select a property that uniquely identifies each item in the track expression. If your data model includes a uniquely identifying property, commonly id or uuid, use this value. If your data does not include a field like this, strongly consider adding one.

For static collections that never change, you can use $index to tell Angular to track each item by its index in the collection.

If no other option is available, you can specify identity. This tells Angular to track the item by its reference identity using the triple-equals operator (===). Avoid this option whenever possible as it can lead to significantly slower rendering updates, as Angular has no way to map which data item corresponds to which DOM nodes.

Contextual variables in @for blocks

Inside @for blocks, several implicit variables are always available:

Variable Meaning
$count Number of items in a collection iterated over
$index Index of the current row
$first Whether the current row is the first row
$last Whether the current row is the last row
$even Whether the current row index is even
$odd Whether the current row index is odd

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

      
@for (item of items; track item.id; let idx = $index, e = $even) {  <p>Item #{{ idx }}: {{ item.name }}</p>}

The aliasing is useful when nesting @for blocks, letting you read variables from the outer @for block from an inner @for block.

Providing a fallback for @for blocks with the @empty block

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:

      
@for (item of items; track item.name) {  <li> {{ item.name }}</li>} @empty {  <li aria-hidden="true"> There are no items. </li>}

Conditionally display content with the @switch block

While the @if block is great for most scenarios, the @switch block provides an alternate syntax to conditionally render data. Its syntax closely resembles JavaScript's switch statement.

      
@switch (userPermissions) {  @case ('admin') {    <app-admin-dashboard />  }  @case ('reviewer') {    <app-reviewer-dashboard />  }  @case ('editor') {    <app-editor-dashboard />  }  @default {    <app-viewer-dashboard />  }}

The value of the conditional expression is compared to the case expression using the triple-equals (===) operator.

@switch does not have a fallthrough, so you do not need an equivalent to a break or return statement in the block.

You can optionally include a @default block. The content of the @default block displays if none of the preceding case expressions match the switch value.

If no @case matches the expression and there is no @default block, nothing is shown.