Render Angular Lists with @for, track, and @empty
Use stable item identities and show a clear message when an article list is empty.
You are reading a translated version.
Article lists may be reordered when items are added, removed, or filtered. Angular needs stable identities to associate items with their rendered elements.
This example tracks IDs rather than array positions. Two sample articles appear initially. A clear button demonstrates the @empty branch so the no-data state has an intentional message.
Implementation example
import { Component, signal } from '@angular/core';
type Article = { id: number; title: string };
@Component({
selector: 'app-reading-list',
standalone: true,
template: `
<button (click)="clear()">Clear list</button>
<ul>
@for (article of articles(); track article.id; let index = $index) {
<li>{{ index + 1 }}. {{ article.title }}</li>
} @empty {
<li>No articles in this reading list.</li>
}
</ul>
`,
})
export class ReadingList {
articles = signal<Article[]>([
{ id: 11, title: 'Learning components' },
{ id: 24, title: 'Working with signals' },
]);
clear(): void {
this.articles.set([]);
}
}
Check the result
Verify that both titles appear with numbers 1 and 2. Clear the list and inspect the empty message. As an exercise, add a reverse-order button that calls update(items => [...items].reverse()) from a TypeScript method.
Display numbering can use $index while identity still uses id. Avoid duplicate IDs or IDs regenerated on every render. Database-backed items can use their existing primary keys. An empty list does not represent loading or failure; handle those separately when adding API requests.
