Angular, again
You wrote Angular for years, and then it was rebuilt around you: signals instead of zones, standalone components instead of modules, built-in control flow instead of directives. Every topic here shows the old way next to the current one, and the current one runs on the page.
Angular 2022
// 2022: state lived in a service
@Injectable({ providedIn: 'root' })
export class CounterService {
private count = new BehaviorSubject(0);
readonly count$ = this.count.asObservable();
increment(): void {
this.count.next(this.count.getValue() + 1);
}
}
@Component({
template: '{{ count$ | async }}',
})
export class CounterComponent {
readonly count$ = inject(CounterService).count$;
}
A service, a BehaviorSubject, an async pipe, and a subscription to clean up.
Angular 22
import { Component, computed, signal } from '@angular/core';
@Component({
selector: 'app-demo-signal-counter',
imports: [],
templateUrl: './signal-counter.html',
styleUrl: './signal-counter.css',
})
export class SignalCounter {
protected readonly count = signal(0);
protected readonly double = computed(() => this.count() * 2);
protected increment(): void {
this.count.update((value) => value + 1);
}
protected reset(): void {
this.count.set(0);
}
}
count() = 0 · double() = 0
What changed while you were away
- Signals are the default way to hold state
signal(), computed() and effect() replace most manual change-detection bookkeeping. An input is a signal, a route parameter can be a signal, and HTTP can return one.
- Zoneless is the default
No zone.js, no patched browser APIs. Angular tracks what changed through signals and the template, not by monkey-patching setTimeout.
- Components are standalone
No NgModule for a normal app, no declarations array. A component imports exactly what its own template uses.
- New template syntax
@if, @for and @switch replace *ngIf, *ngFor and *ngSwitch, and track is mandatory for @for — a compile error instead of a silent re-render.
- inject() instead of constructor parameters
Dependencies are pulled in where they are needed, which makes inheritance, guards and small composable helpers straightforward.
- Data loading is built in
resource() and httpResource() model the loading / success / error lifecycle of a fetch as signals, so a template can render the three states directly.
Read it in order
Start here
- Orientation
What stayed the same, what changed, and the order to read this site in.
Foundations
- Standalone components
No `NgModule`, no `declarations` array, no shared module to keep in sync. A component imports exactly what its own template uses.
- The component contract
How data gets in, how events get out, and why `ngOnChanges` is no longer part of the answer.
Reactivity
- Signals
A value plus a list of interested readers. That is the whole mechanism — and it is the one change that makes the rest of Angular 22 easier to understand.
Templates
- Templates & control flow
`@if`, `@for` and `@switch` are syntax now, not directives shipped in a shared module. Plus `@let`, `@defer`, and the v22 additions to the expression syntax.
DI & Routing
- Dependency injection
`inject()` in a field initialiser instead of a constructor parameter, `@Service()` instead of the `providedIn` incantation, and providers you can compose as plain data.
- Routing
`provideRouter` instead of `RouterModule.forRoot`, route titles as data, params bound straight into signal inputs, and guards that are just functions.
Data
- HTTP & async data
`resource()` turns "fetch, show, handle failure" into one object with signals for each state — instead of a loading boolean, an error field, and a subscription to remember.
- Forms
Typed reactive forms are still here and still good. Signal Forms are the new option: validators and submit state as signals, bound with one directive.
Modern runtime
- Zoneless change detection
`zone.js` monkey-patched `setTimeout`, `addEventListener`, `XMLHttpRequest` and promises, then told Angular to check everything. It is gone, and the framework knows what changed from signals and the template instead.
- Performance
Two levers do most of the work: `@defer` for work the user may never need, and `track` for lists. Everything else is measurement.
- SSR & hydration
Rendering the page on the server (or at build time) so the HTML arrives with content in it, then letting the browser take over the same DOM instead of re-rendering it.
- Un-learn & upgrade
The patterns that were right in 2022 and are wrong now, the error each one produces, and the order to do the migration in.
- What to write instead
Every substitution from the 2022 way of writing Angular to the 2026 way, grouped by area. Keep this one open while you migrate.