Skip to content

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: @for renders each item and track makes 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

  1. Understand: property versus attribute versus event binding.
  2. Apply: render complete filtered states.
  3. Analyze: explain view lifecycle when @if changes.
  4. Evaluate: choose a tracking key when server records can be optimistic and unsaved.
  5. 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.