Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Template Syntax and Lifecycle  ›  Lesson

@for, track and @empty

@for 12 minThe @for block renders its content once per item in a collection, requires a track expression that identifies each item, and can show an @empty block when there are no items.

@for, track and @empty

Greenhouse shows a list of plants, and the list changes: plants are added, removed and watered many times a day. Angular must turn an array into elements, and then, on every change, work out which elements to keep. The @for block does both, as long as you tell it how to recognise each plant.

The rule

One block per item, tracked by something that never changes.

<ul>
  @for (p of plants(); track p.id) {
    <li [class.last]="$last">{{ $index + 1 }}. {{ p.name }}</li>
  } @empty {
    <li>No plants yet.</li>
  }
</ul>
  • p of plants() names each item p.
  • track p.id is required. It gives Angular a stable identity for each item.
  • @empty is optional and renders when the collection has no items.

Inside the block, Angular provides helpful values: $index, $first, $last, $even, $odd and $count. You can rename them if loops are nested: @for (p of plants(); track p.id; let i = $index).

Why is track required? When the array changes, Angular compares the tracked keys of the old and new items. Same key: reuse the existing element and just update its text. New key: create an element. Missing key: remove it. With a good key, watering one plant touches one <li>. With a bad key, Angular throws away and rebuilds rows, and any focus, scroll position or half-typed text inside them is lost.

What to track:

  • A unique id from your data. Best choice.
  • $index for a fixed list that never reorders, like a static list of weekdays.
  • Never a value that changes, such as p.lastWatered, and avoid the whole object when you replace objects with new copies.

The shortcut

Ask "What would I call this item on the phone?" Not its colour or when it was last watered, but its name tag that never changes. That is your track expression.

Watering the second plantStep 1 of 4
  1. Before

    Plants 7, 12 and 15 are shown, tracked by id.

This replaces the older *ngFor="let p of plants; trackBy: byId", where tracking was optional and often forgotten.

Drills

Answer fast — trust the rule.

quick drill

Which @for is valid?

quick drill

What is the best track for plants that each have a unique id?

quick drill

When does the @empty block render?

quick drill

How would you print "1.", "2.", "3." before each plant name?

quick drill

Rows lose their typed text every time any plant is watered. What is the likely cause?

Remember

  • @for (item of list; track key) { } @empty { }; track is required.
  • Track a unique, unchanging id; $index only for fixed lists.
  • Helpers: $index, $first, $last, $even, $odd, $count.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWhy does @for need track?

Write the Greenhouse plant list with @for, numbering each plant and showing a message when there are none. Then explain what track p.id does and what happens when a plant is watered if you track something that changes.