Skip to main content

Loops

You will often need to display lists — such as recipes or ingredients. Angular’s @for block is the declarative way to do that.

Example

@for (recipe of recipes; track recipe.id) {
<mc-recipe-preview [recipe]="recipe" />
}
info

Angular has to track items to optimize DOM updates.

In opposition to the old *ngFor directive, the new @for block requires you to specify how to track each item.

Tracking by index

If you want to track items by their index, because they don't have an id and reference equality is not enough, you can use the $index variable:

@for (ingredient of recipe.ingredients; track $index) {
<li>{{ ingredient }}</li>
}

Contextual Variables

You will often need to display item numbers or use odd/even styles. That's why the @for block provides contextual variables:

  • $index — the current item's index,
  • $firsttrue if the current item is the first one,
  • $lasttrue if the current item is the last one,
  • $eventrue if the current item's index is even,
  • $oddtrue if the current item's index is odd.

These variables can be used like this:

@for (step of recipe.steps; track $index) {
<li>#{{ $index + 1 }}. {{ step.description }}</li>
}

Empty Lists

@for supports @empty block to handle the case where the list is empty:

@for (step of recipe.steps; track $index) {
<li>#{{ $index + 1 }}. {{ step.description }}</li>
} @empty {
<p>No ingredients.</p>
}
@empty vs HTML Semantics

In most cases, you will want to loop inside a container element, like ul or ol, while displaying the empty error message outside of it. In that case, prefer using an @if block instead of violating HTML semantics.

<ul>
@for (step of recipe.steps; track step.id) {
<li>#{{ $index + 1 }}. {{ step.description }}</li>
}
</ul>

@if (recipe.steps.length === 0) {
<p role="alert" aria-live="polite">No recipes found.</p>
}
Pragmatic Angular Testing
👨🏻‍🍳 Let's cook some tests →

💰 80€ · 170€ · Lifetime access

Learn how to write reliable tests that survive upgrades and refactorings.