DEV Community

Manthan Ankolekar
Manthan Ankolekar

Posted on

3

Mastering Angular's New Control Flow with TypeScript Code Examples

With the introduction of Angular v17, the framework brings a new control flow syntax that replaces *ngIf, *ngFor, and *ngSwitch with @if, @for, and @switch. This makes Angular templates more readable, maintainable, and closer to JavaScript.

In this blog, we'll explore these features with practical TypeScript examples and how to implement them in real-world Angular applications.

Important Update: The traditional structural directives (*ngIf, *ngFor, and *ngSwitch) will be deprecated in Angular v20. Now is the time to migrate your code to the new control flow syntax.


1. Setting Up an Angular Component

Let's create a simple User Dashboard component that displays user details, a list of orders, and order status.

✅ TypeScript (dashboard.component.ts)

import { Component } from '@angular/core';

interface Order {
    id: number;
    status: 'pending' | 'shipped' | 'delivered';
}

interface User {
    name: string;
    isLoggedIn: boolean;
    role: 'admin' | 'user';
    orders: Order[];
}

@Component({
    selector: 'app-dashboard',
    standalone: true,
    templateUrl: './dashboard.component.html',
})
export class DashboardComponent {
    user: User | null = {
        name: 'John Doe',
        isLoggedIn: true,
        role: 'user',
        orders: [
            { id: 1, status: 'pending' },
            { id: 2, status: 'shipped' },
            { id: 3, status: 'delivered' },
        ],
    };

    toggleUser() {
        this.user = this.user ? null : {
            name: 'John Doe',
            isLoggedIn: true,
            role: 'user',
            orders: [
                { id: 1, status: 'pending' },
                { id: 2, status: 'shipped' },
                { id: 3, status: 'delivered' },
            ],
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Using @if for Conditional Rendering

We'll use @if to check if a user is logged in and display the appropriate UI.

✅ Template (dashboard.component.html)

<button (click)="toggleUser()">Toggle User</button>

@if (user) {
    <h2>Welcome, {{ user.name }}!</h2>
    <p>You are logged in as {{ user.role }}.</p>
} @else {
    <p>Please log in to access your dashboard.</p>
}
Enter fullscreen mode Exit fullscreen mode

✨ Benefits of @if

  • No need for <ng-container> wrappers.
  • Uses a syntax similar to JavaScript if-else.

3. Using @for to Loop Through Orders

We'll display a list of orders using @for.

✅ Template for @for

@if (user) {
    <h3>Your Orders:</h3>
    <ul>
        @for (order of user.orders; track order.id) {
            <li>Order #{{ order.id }} - {{ order.status }}</li>
        } @empty {
            <li>No orders found.</li>
        }
    </ul>
}
Enter fullscreen mode Exit fullscreen mode

✨ Benefits of @for

  • track order.id improves performance.
  • @empty handles cases when there are no items.

4. Using @switch to Handle Order Status

We'll use @switch to display different messages based on order status.

✅ Template

<ul>
    @for (order of user?.orders ?? []; track order.id) {
        <li>
            Order #{{ order.id }} - 
            @switch (order.status) {
                @case ('pending') { <span class="text-warning">Pending</span> }
                @case ('shipped') { <span class="text-info">Shipped</span> }
                @case ('delivered') { <span class="text-success">Delivered</span> }
                @default { <span class="text-muted">Unknown</span> }
            }
        </li>
    }
</ul>
Enter fullscreen mode Exit fullscreen mode

✨ Benefits of @switch

  • Eliminates excessive *ngSwitchCase directives.
  • Closely mirrors JavaScript switch syntax.

5. Full Working Example

✅ Complete Implementation: TypeScript (dashboard.component.ts)

import { Component } from '@angular/core';

interface Order {
    id: number;
    status: 'pending' | 'shipped' | 'delivered';
}

interface User {
    name: string;
    isLoggedIn: boolean;
    role: 'admin' | 'user';
    orders: Order[];
}

@Component({
    selector: 'app-dashboard',
    standalone: true,
    templateUrl: './dashboard.component.html',
})
export class DashboardComponent {
    user: User | null = {
        name: 'John Doe',
        isLoggedIn: true,
        role: 'user',
        orders: [
            { id: 1, status: 'pending' },
            { id: 2, status: 'shipped' },
            { id: 3, status: 'delivered' },
        ],
    };

    toggleUser() {
        this.user = this.user ? null : {
            name: 'John Doe',
            isLoggedIn: true,
            role: 'user',
            orders: [
                { id: 1, status: 'pending' },
                { id: 2, status: 'shipped' },
                { id: 3, status: 'delivered' },
            ],
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ HTML (dashboard.component.html)

<button (click)="toggleUser()">Toggle User</button>

@if (user) {
    <h2>Welcome, {{ user.name }}!</h2>
    <p>You are logged in as {{ user.role }}.</p>

    <h3>Your Orders:</h3>
    <ul>
        @for (order of user.orders; track order.id) {
            <li>
                Order #{{ order.id }} - 
                @switch (order.status) {
                    @case ('pending') { <span class="text-warning">Pending</span> }
                    @case ('shipped') { <span class="text-info">Shipped</span> }
                    @case ('delivered') { <span class="text-success">Delivered</span> }
                    @default { <span class="text-muted">Unknown</span> }
                }
            </li>
        } @empty {
            <li>No orders found.</li>
        }
    </ul>
} @else {
    <p>Please log in to access your dashboard.</p>
}
Enter fullscreen mode Exit fullscreen mode

6. Key Takeaways

More Readable – No more * prefixes, making it JavaScript-like.

Less Boilerplate – No need for extra <ng-container> elements.

Better Performance – Faster change detection and rendering.

Improved Debugging – Clearer syntax simplifies troubleshooting.

Future-Proof – Legacy syntax will be deprecated in Angular v20.


7. How to Enable the New Control Flow?

The new control flow is enabled by default in Angular v17+. If you're using an older version, upgrade your Angular project:

ng update @angular/core @angular/cli
Enter fullscreen mode Exit fullscreen mode

or

ng generate @angular/core:control-flow
Enter fullscreen mode Exit fullscreen mode

Once updated, you can start using @if, @for, and @switch in your templates.


Final Thoughts

Angular's new control flow is a game-changer, making templates cleaner, more readable, and more efficient. With the upcoming deprecation of the old syntax in Angular v20, now is the perfect time to embrace these changes. Whether you're working on a small project or a large enterprise app, adopting this syntax will make your Angular development experience smoother and faster while ensuring your codebase stays current with Angular's evolution.

8. Exploring the Code

Visit the GitHub repository to explore the code in detail.

9. Live Demo

Check out the working example on StackBlitz


10. Additional Resources

Feel free to leave comments or questions below! 👋

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

If this post resonated with you, feel free to hit ❤️ or leave a quick comment to share your thoughts!

Okay