Kala Tech

ΚΑΛΑ • GOOD TECH

Announcing Angular v22: Key Features and Code Examples

The Angular team has officially released Angular v22! This release marks a significant milestone in the framework's evolution, focusing heavily on performance-centric defaults, stabilizing modern reactive primitives, and refining dependency injection.

Whether you're starting a new application or preparing to migrate an existing codebase, understanding these new features will help you write faster, cleaner, and more maintainable code. Let's dive into the major additions with practical code examples.


1. OnPush Change Detection by Default

To improve application performance and guide developers toward best practices, ChangeDetectionStrategy.OnPush is now the default for all new components.

Instead of constantly checking the entire component tree for updates, OnPush components only re-evaluate when their inputs change, signals emit, or events are explicitly triggered.

The New Default Behavior

When you generate a component in Angular v22, it will behave as OnPush implicitly:

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

@Component({
  selector: 'app-user-card',
  template: `
    <div>
      <h3>Name: {{ name() }}</h3>
    </div>
  `
  // changeDetection: ChangeDetectionStrategy.OnPush is implied by default!
})
export class UserCardComponent {
  name = input.required<string>();
}

Opting Out: Using ChangeDetectionStrategy.Eager

If you need a component to use the old eager change detection behavior (previously known as Default), you must set it explicitly:

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

@Component({
  selector: 'app-legacy-card',
  template: `...`,
  // Explicitly request eager check cycles
  changeDetection: ChangeDetectionStrategy.Eager
})
export class LegacyCardComponent {}

2. The New @Service() Decorator

Angular v22 introduces the @Service() decorator as a cleaner, more ergonomic alternative to the traditional @Injectable({ providedIn: 'root' }) syntax for defining application-wide singletons.

Before: Injectable Decorator

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient) {}
}

After: Service Decorator

import { Service, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Service()
export class UserService {
  // Constructor injection is bypassed entirely!
  private http = inject(HttpClient);
}

3. Asynchronous Dependency Injection: injectAsync()

For applications with heavy dependencies (such as large PDF generation modules or graphing libraries), Angular v22 introduces injectAsync(). This API allows you to lazily load and resolve DI services asynchronously on-demand rather than bundling them in the initial payload.

Example: Lazy Loading a Report Exporter

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

@Component({
  selector: 'app-report-panel',
  template: `<button (click)="onExport()">Generate Report</button>`
})
export class ReportPanelComponent {
  // Define the loader using a dynamic import
  private loadExporter = injectAsync(
    () => import('./report-exporter.service').then(m => m.ReportExporterService)
  );

  async onExport() {
    // The dependency is fetched and resolved in the DI container on demand
    const exporter = await this.loadExporter();
    exporter.exportPdf();
  }
}

4. Stable Signal-Based APIs (Forms & Resources)

Several reactive APIs that were experimental in previous versions have officially graduated to stable status in v22:

Example: Reacting to Changes with httpResource

import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';

@Component({
  selector: 'app-user-search',
  template: `
    <input (input)="onInput($event)" placeholder="Search users..." />
    
    @if (userResource.isLoading()) {
      <p>Loading...</p>
    } @else {
      <ul>
        @for (user of userResource.value(); track user.id) {
          <li>{{ user.name }}</li>
        }
      </ul>
    }
  `
})
export class UserSearchComponent {
  searchQuery = signal('');

  // Automatically triggers a refetch whenever searchQuery changes!
  userResource = httpResource(() => `/api/users?q=${this.searchQuery()}`);

  onInput(event: Event) {
    const input = event.target as HTMLInputElement;
    this.searchQuery.set(input.value);
  }
}

5. Tooling and Runtime Updates

In addition to API enhancements, Angular v22 updates several core tools and dependencies:

Conclusion

Angular v22 represents a significant step toward a fully reactive, signal-first ecosystem. By adopting defaults like OnPush, streamlining service creation with @Service(), and lazy loading with injectAsync(), you can build applications that load faster and operate with high runtime efficiency.