Skip to the solution
EasyFrontend11 min read

Explain the new Control Flow (@if, @for, @switch) and how it compares to structural directives.

940 views

The problem

Question presented to candidate: "Angular templates now have @if, @for and @switch blocks. Explain what they are, how they differ from the older *ngIf / *ngFor / ngSwitch structural directives, and why the team added them."

What a strong answer should cover:

  • Control flow blocks are template syntax understood by the compiler, not directives: nothing to import, nothing instantiated at runtime.
  • Structural directives (*ngIf, *ngFor) are classes that receive an ng-template and create or destroy embedded views through ViewContainerRef.
  • @if supports @else if / @else inline and as aliasing; @for requires track and has @empty plus $index, $first, $last, $even, $odd, $count; @switch uses @case / @default with strict equality.
  • Better type narrowing, fewer wrapper ng-template / ng-container elements, a faster list diffing algorithm.
  • Status: introduced in v17, stable in v18; NgIf, NgForOf and NgSwitch are deprecated since v20 but still work in v22.
  • Structural directives remain the mechanism for custom structural behaviour; only the three built-ins were replaced.

Clarifying questions expected:

  • "Are we talking about a new codebase, or migrating templates that already use *ngIf?"
  • "Do you want the template syntax, or what the compiler generates for each?"

Code / implementation expected: Yes — a template using all three blocks, ideally with @empty and a track expression.

  • control-flow
  • directives

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

11 min read · 11 sections

Read the code

Angular@if / @else if, @for with track and @empty, and @switch in one component
import { Component, computed, signal } from "@angular/core";

type Order = { id: number; item: string; status: "paid" | "shipped" | "refunded" };

// Built-in control flow: no NgIf / NgFor / NgSwitch import needed.
@Component({
  selector: "app-root",
  template: `
    @if (loading()) {
      <p>Loading orders...</p>
    } @else if (orders().length > 3) {
      <p>Busy day: {{ orders().length }} orders</p>
    } @else {
      <p>{{ orders().length }} orders</p>
    }

    <ul>
      @for (o of orders(); track o.id; let i = $index, last = $last) {
        <li>
          {{ i + 1 }}. {{ o.item }} -
          @switch (o.status) {
            @case ("paid") { <b>paid</b> }
            @case ("shipped") { <b>on its way</b> }
            @default { <b>refunded</b> }
          }
          @if (last) { (latest) }
        </li>
      } @empty {
        <li>No orders yet</li>
      }
    </ul>

    <button (click)="loading.set(false)">Finish loading</button>
    <button (click)="add()">Add order</button>
    <button (click)="orders.set([])">Clear</button>
  `,
})
export class AppComponent {
  loading = signal(true);
  orders = signal<Order[]>([
    { id: 1, item: "Keyboard", status: "shipped" },
    { id: 2, item: "Mouse", status: "paid" },
  ]);
  nextId = computed(() => Math.max(0, ...this.orders().map((o) => o.id)) + 1);

  add() {
    const id = this.nextId();
    this.orders.update((list) => [...list, { id, item: "Cable " + id, status: "refunded" }]);
  }
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 1 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextEasy

What is the difference between the constructor and ngOnInit?

Continue