Showing posts with label Angular. Show all posts
Showing posts with label Angular. Show all posts

Angular v21 Released — Signal Forms, ARIA Components, AI Tools & More

Angular v21 — Tutorial: Signal Forms, Angular Aria, MCP & Zoneless (Hands-On)

Explainer Published: 18 November 2025 • Author: The DotNet Office

A short, practical tutorial showing how to get started with the main Angular v21 features and small working examples you can paste into your project.

What you'll learn

  • How to scaffold a new Angular v21 project (commands)
  • A Signal Forms login form example
  • Using an Angular Aria combobox (headless accessible UI)
  • How to use the MCP server in read-only mode
  • Notes on zoneless apps and Vitest

Prerequisites

Make sure you have:

  • Node.js (>= 18 recommended)
  • npm or yarn
  • Angular CLI (latest)
  • Basic TypeScript and Angular knowledge

Note: Replace `ng` commands with your preferred package manager if needed (npm/yarn).

1) Create a new Angular v21 project

Scaffold a fresh app (the CLI will create a project configured for v21 defaults):

npx @angular/cli@latest new angular-v21-demo
cd angular-v21-demo
npm install

If you already have an app, use ng update to migrate to v21.

2) Signal Forms — Example: Login form

Signal Forms let you manage form state with signals instead of FormGroup. Here's a minimal login form using the new API (example is simplified).

Install (if needed) — the forms signals API is provided from Angular forms package:

npm install @angular/forms

login.component.ts

import { Component } from '@angular/core';
import { signal } from '@angular/core';
import { form, Field } from '@angular/forms/signals';

@Component({
  standalone: true,
  selector: 'app-login',
  imports: [Field],
  templateUrl: './login.component.html'
})
export class LoginComponent {
  // simple reactive model as a signal
  model = signal({ email: '', password: '' });

  // create a Signal Form instance bound to the model
  loginForm = form(this.model);

  onSubmit() {
    // loginForm.value() or access model()
    console.log('Submitting', this.model());
    // send to server, show validation, etc.
  }
}

login.component.html

<form (ngSubmit)="onSubmit()" >
  <label>Email</label>
  <input [field]="loginForm.email" type="email" />

  <label>Password</label>
  <input [field]="loginForm.password" type="password" />

  <button type="submit">Sign in</button>
</form>

This approach reduces boilerplate and integrates validation in a predictable, type-safe way. For custom controls, signal bindings avoid many previous complexities around ControlValueAccessor.

3) Angular Aria — Example: Accessible Combobox

Angular Aria provides headless (unstyled) primitives built with ARIA and keyboard interactions in mind. Install and use them as primitives for your custom UI.

npm i @angular/aria

combobox.component.ts (simplified)

import { Component, signal } from '@angular/core';
/* pseudo-imports — follow official Aria docs for actual API names */
import { ComboboxDirective } from '@angular/aria';

@Component({
  standalone: true,
  selector: 'app-combobox',
  template: `
    <div aria-label="Country selector">
      <input [ariaCombobox]="items" [value]="query()" (input)="onInput($event)" />
      <ul role="listbox">
        <li *ngFor="let it of filteredItems()" role="option">{{ it }}</li>
      </ul>
    </div>
  `
})
export class ComboboxComponent {
  query = signal('');
  items = ['India','United States','Canada','Australia','Germany'];
  filteredItems = () => this.items.filter(i => i.toLowerCase().includes(this.query().toLowerCase()));

  onInput(e: Event) {
    const v = (e.target as HTMLInputElement).value;
    this.query.set(v);
  }
}

Angular Aria ensures keyboard navigation, focus management and ARIA attributes are correct — you only style it to match your UI.

4) MCP Server — quick read-only example

The Model Context Protocol (MCP) server allows LLM agents to query your workspace. Run it in a safe read-only mode while experimenting:

# Start the MCP server in read-only mode (CLI)
ng mcp --read-only

An AI agent connected to MCP can query project structure, docs, or suggest migration steps. Keep the server in read-only for safety when experimenting.

5) Zoneless apps & Enabling zones (if needed)

By default v21 new projects are zoneless — Angular relies on Signals + explicit update triggers. This yields smaller bundles and more predictable rendering.

If you need Zone-based detection temporarily, add the provider:

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

bootstrapApplication(App, {
  providers: [ provideZoneChangeDetection() ]
});

Use migration schematics for large apps rather than flipping the provider manually across many modules.

6) Quick: Vitest example (test a service)

Angular v21 defaults to Vitest for new projects. Minimal example test for a simple service:

// greeting.service.ts
export class GreetingService {
  greet(name: string) { return `Hello, ${name}`; }
}

// greeting.spec.ts (Vitest)
import { describe, it, expect } from 'vitest';
import { GreetingService } from './greeting.service';

describe('GreetingService', () => {
  it('returns greeting', () => {
    const svc = new GreetingService();
    expect(svc.greet('Alice')).toBe('Hello, Alice');
  });
});

Run tests with npm test or npx vitest depending on your setup.

7) Quick migration tips

  • Use ng update to apply official migration schematics.
  • Try Signal Forms and Aria in a feature branch or isolated module first.
  • Use the MCP tool onpush_zoneless_migration to generate migration suggestions.
  • Migrate tests to Vitest using the provided refactor schematic.

Final notes

Angular v21 is focused on modern reactive patterns, accessibility primitives, and AI-enhanced development workflows. Start small: adopt Signal Forms and Aria in a feature module, use MCP read-only to discover how AI can help your codebase, and migrate tests to Vitest for a faster developer experience.

If you'd like, I can:

  • Convert any of the above examples into a downloadable StackBlitz-ready project
  • Write a full migration checklist for a production app
  • Create SEO-tailored headings and meta tags specifically for your Blogger theme

Angular v20 Released - What's New? | Angular v20 Now released

Angular v20 Released - What's New?

🚀 Angular v20 is Officially Released!

Angular v20 is now available as of May 29, 2025, introducing major updates focused on performance, developer experience, and modern web practices.

✅ Stabilizing APIs

Purpose: Reactive state management without RxJS

The reactive programming model is now stable with production-ready APIs like effect(), linkedSignal(), and toSignal().

import { signal, effect } from '@angular/core';

const counter = signal(0);

effect(() => {
  console.log('Counter changed to:', counter());
});

counter.set(1); // Logs: Counter changed to: 1
counter.update(c => c + 1); // Logs: Counter changed to: 2

⚡ Zoneless Change Detection (Developer Preview)

Purpose: Run Angular apps without Zone.js for better performance

Angular v20 introduces a preview of zoneless change detection, improving performance and simplifying debugging.

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

bootstrapApplication(AppComponent, {
  providers: [provideExperimentalZonelessChangeDetection()],
});

🌐 Enhanced Server-Side Rendering (SSR)

Purpose: Faster loading using Incremental Hydration and Route-Level Rendering

Features like incremental hydration and route-level rendering are now stable.

export const routes: Routes = [
  {
    path: 'products',
    loadComponent: () => import('./products.component').then(m => m.ProductsComponent),
    data: { ssrRender: true }, // Render this route server-side
  }
];

🛠️ Chrome DevTools Integration

Purpose: Debug performance with Angular-specific data in the Chrome Performance tab

Angular-specific profiling data is now available directly in Chrome DevTools’ Performance tab. Includes:

  • Component lifecycle timings
  • Change detection events
  • Template rendering phases

No extra setup—works automatically in development mode.

🧹 Updated Style Guide and Naming Conventions

Purpose: Cleaner file names without suffixes

Angular CLI no longer adds suffixes to file names by default.

# Before (Angular v19)
ng generate component user
# Generates: user.component.ts

# After (Angular v20)
ng generate component user
# Generates: user.ts (no .component suffix)

You can override with:

ng generate component user --style-guide-compat=false

🧪 Extended Type Checking in Host Bindings

Purpose: Safer bindings in directives

Improved type safety and support for host bindings and listeners.

@Directive({
  selector: '[appHighlight]',
  host: {
    '[class.highlighted]': 'isHighlighted' // Type-checked
  }
})
export class HighlightDirective {
  isHighlighted = true;
}

✨In short- What’s New in Angular 20?

  • 1️⃣ Stable Signals API
    Simpler and faster reactive state management — no RxJS needed!
  • 2️⃣ Zoneless Change Detection (Preview)
    Boost performance by running Angular apps without Zone.js.
  • 3️⃣ Enhanced SSR
    Enjoy lightning-fast loads with incremental hydration and route-level rendering.
  • 4️⃣ Chrome DevTools Integration
    Deep Angular insights now directly in Chrome’s performance panel.
  • 5️⃣ Simplified File Naming
    No more .component.ts clutter — cleaner, more intuitive naming!
  • 6️⃣ Improved Type Checking
    Smarter host bindings with safer, stricter type checking.

Template Local Variable with @let Block | @let in Angular

  @let directive, enhancing template syntax by allowing variable declarations directly within HTML templates. This feature simplifies template logic by providing more flexibility and clarity, reducing the need for complex workarounds.

👉👉👉Angular18 new features



Template Local Variable with @let Block: A new feature in templates allows using the @let directive to declare local variables within templates, simplifying data binding and improving template readability.

Without @let variable: Creating local variables within templates was often verbose and required using additional directives or components.

Previously, you would often use directives ngIf combined with the as keyword to declare and use a variable within a template. For example:


<ng-container *ngIf="user as currentUser">
  <div>{{ currentUser.name }}</div>
</ng-container>

C#

While this method works, it has limitations, especially when dealing with falsy values like 0. If the value is 0, the content inside ngIf won't render because 0 is considered falsy.

with @let variable:

Angular 18 introduces the @let directive, which simplifies the declaration of local variables within templates.

The @let directive allows you to declare a variable directly within the template, independent of its truthiness. This makes the template logic more straightforward and expressive. Here's how you can use @let:


<div>
  @let PrintName = 'myName, ' + name + '!';
  <h1>{{ PrintName }}</h1>
</div>

C#



<div>
  @let points = (points$ | async) ?? 0;
  <h1>You have: {{ points }} points!</h1>
</div>


C#

This ensures that even if points is 0, the content will still render correctly.

Benefits and Use Cases

  1. Handling Falsy Values: As shown in the example, @let this helps manage cases where falsy values might disrupt the template rendering logic.

  2. Complex Expressions: Simplify templates by storing complex expressions in a variable.

@let someField = someService.someSignal().someProperty.someOtherProperty;
<div>{{ someField }}</div>


C#

3. Control Flow Directives: Combine @let with control flow directives like @if to streamline logic.

<div>
  @let user = user$ | async;
  @if (user) {
    <h1>{{ user.name }}</h1>
  }
</div>


C#

4. Iterating with @for: Reduce code duplication in loops.

<mat-selection-list>
  @for (item of items(); track item.id) {
    @let isSelected = item.id === selectedId();
    <mat-list-option [selected]="isSelected" [class.selected]="isSelected">
      {{ item.text }}
      @if (isSelected) {
        <span>(selected)</span>
      }
    </mat-list-option>
  }
</mat-selection-list>


C#


5. Ternary Operators and Math: Use @let with operators to make calculations directly in templates.

<div>
  @for (game of games; track game.id) {
    @let points = calcPoints(game.points > 0 ? game.points : 0);
    <h1>You have: {{ points }} points!</h1>
  }
</div>

C#

Another Example

Calculate the Item Price


<div *ngFor="let item of items">
  @let totalPrice = item.price * item.quantity;
  @let date = (new Date(item.date)).toLocaleDateString();
  <p>{{ item.name }} - Total: {{ totalPrice }} on date {{date}}</p>
</div>


C#

Benefit:

This new syntax makes templates more readable and easier to manage by reducing boilerplate code and improving data-binding practices​

The @let the directive in Angular 18 significantly enhances template flexibility and readability. It reduces the need for complex directives and workarounds, making code cleaner and more maintainable​