~3 min de lecture
Angular 21.1 — Ce qui change vraiment pour ton code
Angular 21.1 vient de sortir ce 14 janvier 2026. Derrière le numéro de version "minor", cette release apporte des changements que tu vas utiliser au quotidien : le @switch devient enfin pratique, le spread arrive dans les templates, et Signal Forms continue sa maturation.
Voyons ce qui mérite ton attention.
Le @switch qui aurait dû exister depuis le début
Si tu as déjà écrit un @switch avec plusieurs cases identiques, tu connais la frustration :
<!-- Avant : la répétition pénible -->
@switch (status) {
@case ('pending') {
<app-loading />
}
@case ('processing') {
<app-loading />
}
@case ('completed') {
<app-success />
}
}
Angular 21.1 introduit le fall-through comme en JavaScript natif :
<!-- Angular 21.1 : enfin propre -->
@switch (status) {
@case ('pending')
@case ('processing') {
<app-loading />
}
@case ('completed') {
<app-success />
}
}
Un case vide "tombe" vers le suivant. Simple, intuitif, et ça aurait dû être là dès le départ.
Spread syntax dans les templates
Autre ajout qui va simplifier ton code : le spread fonctionne maintenant directement dans les expressions template.
<!-- Merge d'objets -->
<app-config [options]="{...defaultOptions, ...customOptions}" />
<!-- Concat d'arrays -->
<app-list [items]="[...baseItems, ...additionalItems]" />
Fini les méthodes utilitaires dans le controller juste pour merger deux objets :
// Avant : le boilerplate inutile
@Component({...})
export class Config {
defaultOptions = { theme: 'dark', lang: 'fr' };
customOptions = input<Partial<Options>>();
// Cette méthode n'a plus raison d'exister
getMergedOptions() {
return { ...this.defaultOptions, ...this.customOptions() };
}
}
// Angular 21.1 : directement dans le template
@Component({
template: `<app-config [options]="{...defaultOptions, ...customOptions()}" />`
})
export class Config {
defaultOptions = { theme: 'dark', lang: 'fr' };
customOptions = input<Partial<Options>>();
}
Signal Forms : le renommage à anticiper
Si tu expérimentes avec Signal Forms, attention : breaking change sur la directive.
// Angular 21.0
<input [field]="loginForm.email" />
// Angular 21.1
<input [formField]="loginForm.email" />
L'import change aussi :
import { form, FormField, required, email } from '@angular/forms/signals';
@Component({
imports: [FormField],
template: `
<input type="email" [formField]="loginForm.email" />
<input type="password" [formField]="loginForm.password" />
`
})
export class Login {
loginModel = signal({ email: '', password: '' });
loginForm = form(this.loginModel, (f) => {
required(f.email);
email(f.email);
required(f.password);
});
}
Ce renommage aligne la nomenclature avec les directives existantes (formControl, formControlName, formGroup). Un schematic de migration devrait gérer ça automatiquement via ng update.
Autres améliorations Signal Forms
| Amélioration | Impact |
|---|---|
| Support readonly arrays | Les arrays immutables fonctionnent correctement |
| Cleanup listeners async | Plus de fuites sur les validations avec timeout |
| Focus programmatique | field.focus() disponible depuis le field state |
Router : la fonction isActive() standalone
Router.isActive() est désormais déprécié. Place à une fonction standalone qui retourne une computed signal :
// Avant : injection + méthode
@Component({...})
export class Nav {
private router = inject(Router);
isHomeActive() {
return this.router.isActive('/home', { exact: true });
}
}
// Angular 21.1 : fonction standalone + signal
import { isActive } from '@angular/router';
@Component({
template: `
<a [class.active]="isHomeActive()">Home</a>
`
})
export class Nav {
isHomeActive = isActive('/home');
}
Plus propre, plus réactif, et pas besoin d'injecter le Router.
Navigation API (expérimental)
Angular commence à utiliser la Navigation API native en remplacement du wrapper sur History API. Avantages attendus : transitions plus fluides et meilleure gestion de l'historique. Le fallback sur History API est automatique pour les navigateurs non compatibles.
Cleanup automatique des EnvironmentInjector
En expérimental : les injectors associés aux routes inactives sont automatiquement libérés. Si ton app a beaucoup de routes avec des providers spécifiques, ça peut réduire la consommation mémoire sur les sessions longues.
Image Loaders : transformations custom
Les loaders pour Cloudflare, Cloudinary, ImageKit et Imgix supportent maintenant des transformations personnalisées. Tu peux fine-tuner la livraison (format, qualité, crops) tout en profitant de l'optimisation automatique d'Angular.
Bug fix critique : fuites mémoire animations
Si ton app utilise beaucoup d'animations ou tourne longtemps sans refresh, cette release corrige des fuites mémoire dans le cleanup des view data. Raison suffisante pour upgrader même si les nouvelles features ne t'intéressent pas.
Récap : ce qu'il faut retenir
| Nouveauté | Status | Impact |
|---|---|---|
@switch fall-through |
Stable | Quotidien |
| Spread dans templates | Stable | Quotidien |
[formField] (ex [field]) |
Expérimental | Breaking si tu utilises Signal Forms |
isActive() standalone |
Stable | Remplace Router.isActive() |
| Navigation API | Expérimental | Transparent pour l'instant |
| Fix fuites animations | Stable | Critique pour apps longue durée |
Migration
ng update @angular/core @angular/cli
Si tu utilises Signal Forms, le schematic devrait gérer le renommage field → formField. Sinon, c'est une mise à jour sans friction.
Angular 21.1 n'est pas une révolution, mais ces ajouts au control flow et aux templates vont réduire le boilerplate au quotidien. Le spread syntax dans les templates à lui seul justifie la mise à jour.