Lesson 2 — Templates and control flow¶
Objective¶
Render searchable topic cards with type-checked bindings, complete UI states, and stable DOM identity.
Prerequisites¶
Standalone component imports, TypeScript narrowing, and semantic HTML.
Mental model¶
Angular evaluates template expressions against component state and updates affected bindings. Built-in control flow creates, retains, moves, or destroys views. Tracking tells Angular which domain item owns each view.
Why it exists¶
Declarative bindings connect state to browser/component APIs; stable identity preserves focus, child state, animation continuity, and correctness during collection changes.
Working model:
@forrenders each item andtrackmakes updates efficient.Engineering reality: the key is a correctness contract between a domain entity and a retained view/DOM subtree, not merely a speed hint.
Minimal example¶
@for (topic of filteredTopics(); track topic.id) {
<article>{{ topic.title }}</article>
} @empty {
<p>No matching topics.</p>
}
At the DOM boundary, accept Event and narrow event.target before reading value.
Real-world usage¶
Search results, editable tables, dashboards, and virtualized collections all depend on correct identity and complete loading/empty/error states.
Common mistakes¶
- tracking reorderable data by
$index; - confusing properties with attributes;
- nesting interactive elements;
- mutating source data to represent a filter;
- trusting displayed text while retained child state belongs to another row.
Mini lab¶
Task: Define a readonly topic model; render cards with @for, stable IDs, interpolation, property/event/class bindings, @empty, @if, and @switch; add case-insensitive trimmed search.
Constraints: no any, index tracking, invalid interactive nesting, or destructive filtering of source topics.
Expected result: search preserves source data, empty state is understandable, and reordering preserves row state.
Hint 1
Derive the visible collection from source topics and query.
Hint 2
Treat the item ID as the identity of the whole retained view, including controls and child components.
Solution direction — last resort
Use @for (topic of filteredTopics(); track topic.id) and an @empty block. Narrow EventTarget at the DOM boundary.
Verification¶
Run the build to catch a misspelled property. Add an uncontrolled input to each row, switch temporarily to $index, reorder, and explain the wrong retained value before restoring stable identity.
Mastery evidence: predict which DOM node survives a reorder and fix the identity bug without trial-and-error edits.
Bloom challenge¶
- Understand: property versus attribute versus event binding.
- Apply: render complete filtered states.
- Analyze: explain view lifecycle when
@ifchanges. - Evaluate: choose a tracking key when server records can be optimistic and unsaved.
- Create: design an accessible, filterable list whose URL preserves state.
Summary¶
Bindings target concrete APIs; control flow manages views; stable domain keys preserve view identity and user state.
Spaced review¶
Lesson 3 retrieves ownership across child boundaries. Lesson 11 repeats the identity experiment under load.
What comes next¶
Continue to component communication.