Toutes les nouveautés d'Angular 18
Angular 18 vient de sortir. Quelles sont les nouveautés apportées par cette version majeure ? Découvrons les !
Au sommaire :
- Breaking change : le compilateur d’Angular nécessite Typescript 5.4
- Les opérateurs de flux et defer sont désormais “stable”
- Valeurs par défaut lors de la projection de contenu
- Route.redirectTo peut désormais être une fonction
- Un router guard peut retourner un RedirectCommand
- Changement de détection sans zone.js (expérimental)
- Changements d’états des contrôles de formulaires
- Dépréciation de HttpClientModule
- Angular.dev devient le site de documentation officiel
- Sources et liens
Breaking change : le compilateur d’Angular nécessite Typescript 5.4
Le “compiler” d’Angular 18 (@angular/compiler-cli) nécessite désormais la version 5.4 de Typescript. Cela pourrait
poser quelques soucis lors de la mise à jour si vous avez des packages qui nécessitent une version inférieure.
Typescript étant connu pour éviter à tout prix les breaking changes, cela ne devrait en réalité pas poser de problèmes
lors de l’éxécution de votre projet, mais il faudra probablement ignorer et/ou fixer quelques erreurs lors de votre
npm update !
Les opérateurs de flux et defer sont désormais “stables”
Si vous non plus vous ne pouvez plus écrire un template sans @if, @for, @defer et consorts : bonne nouvelle.
Ces opérateurs étaient en “développeur preview” avec Angular 17, leur API est désormais “stable” avec Angular 18 !
Valeurs par défaut lors de la projection de contenu
La projection de contenu est une mécanique permettant de récupérer ce qui est placé entre les balises HTML d’un composant afin de l’afficher où on le souhaite dans le-dit composant.
Prenons l’exemple d’une carte Pokémon. Je souhaite avoir un composant <pokemon-card>...</pokemon-card> auquel je
veux fournir du contenu HTML pour afficher le nom de la carte, son coût, une image, une description et une éventuelle
citation ou crédit en bas de carte. Si l’une de ces informations n’est pas fournie, il serait intéressant d’avoir un
contenu affiché par défaut.
Avant Angular 18
Auparavant si vous ajoutiez du contenu dans un <ng-content> vous obteniez une erreur, par exemple :
@Component({
selector: 'pokemon-card',
template: `<ng-content>Contenu par défaut<ng-content>`
})
export class PokemonCard {}Vous obtenez l’erreur suivante :
✘ [ERROR] NG5002: <ng-content> element cannot have content. [plugin angular-compiler]
src/main.ts:16:6:
23 │ <ng-content>Contenu par défaut ?</ng-content>
╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
En réalité, il y a des façons d’y arriver, par exemple à l’aide d’un @ContentChild().
À partir d’Angular 18
À partir d’Angular 18, le code ci-dessus est fonctionnel et la valeur passée dans la balise <ng-content> sera affichée
si aucun contenu n’est fourni dans les balises du composant.
<pokemon-card></pokemon-card>Aucun contenu n’est fourni au composant PokemonCard, donc “Contenu par défaut” sera affiché.
<pokemon-card>
<strong>Eclair :</strong> lance une attaque électrique sur son adversaire.
</pokemon-card>Affichera : Eclair : lance une attaque électrique sur son adversaire.
Et enfin…
<pokemon-card>
@if (false) {
<em>Jamais affiché</em>
}
</pokemon-card>… n’affichera rien (n’affichera pas le contenu par défaut) ! Et oui car même s’il est vide, du contenu est fourni au composant.
Route.redirectTo peut désormais être une fonction
La fonction de redirection prend en paramètre un ActivatedRouteSnapshot et doit retourner l’URL sous forme de chaîne
de caractères ou un UrlTree.
export const routes: Routes = [
// ...,
{
path: 'poke-monsters', // ancienne route
redirectTo: ({ queryParams }) => {
const pokemonId = queryParams['id'];
if (pokemonId) {
return `/pokemon/${pokemonId}`;
} else {
return `/pokemons`;
}
}
},
// ...,
];Un router guard peut retourner un RedirectCommand
Afin d’effectuer une redirection dans un guard, il est maintenant possible de retourner un object de type
RedirectCommand, prenant à la construction un UrlTree :
{
path: '/old-url',
component: SuperComponent,
canActivate: [
() => new RedirectCommand(router.parseUrl('/new-url'), {skipLocationChange: true}),
],
}Les options, passées en second paramètre du constructeur, sont un objet de type NavigationBehaviorOptions.
Documentation de RedirectCommand.
Expérimental : changement de détection sans zone.js
Si vous avez même peu d’expérience avec Angular, il y a de fortes chances que vous soyez déjà tombé sur une erreur
incompréhensible provenant de zone.js. Pour simplifier un peu, ce vendor est chargé de rapporter tous les changements
et événements d’une “zone” donnée (en général, la zone est votre page web). Angular s’en servait donc pour effectuer
la détection de changement.
Avec des travaux réalisés depuis quelques années et l’arrivée des signaux, il est désormais possible de d’utiliser
Angular sans zone.js. Pour cela, il faut appeler provideExperimentalZonelessChangeDetection() lors du démarrage de
l’application (bootstrap) :
bootstrapApplication(App, {
providers: [
provideExperimentalZonelessChangeDetection()
]
});Vous pouvez désormais retirer zone.js du fichier angular.json. Le retrait de zone.js permet notamment :
- d’accélérer le rendu initial de l’application
- réduire le poids global de l’application
- avoir plus de contrôle sur la détection de changement avec la stratégie
OnPushetChangeDetectorRef.markForCheck - combiner des micro-frontends plus facilement (ils ne sont plus dans des zones différentes)
- éviter d’avoir des erreurs incompréhensibles :)
La migration sera plus facile si vos composants ont déjà la stratégie de détection de changement OnPush. Alors si ce
n’est pas le cas, je vous suggère de les convertir au plus vite !
Changements d’états des contrôles de formulaires
Une nouvelle propriété est disponible sur FormControl, FormGroup et FormArray : events.
Il s’agit d’un observable permettant d’être informé sur les différents changements d’états : valeur, touch,
pristine et son état de validation. Son utilisation est très simple :
const nameControl = new FormControl<string|null>('name', Validators.required);
nameControl.events.subscribe(event => {
// process the individual events
});Dépréciation de HttpClientModule
Importer HttpClientModule dans un module ou composant est désormais déprécié. Il faut utiliser la fonction
provideHttpClient() dans vos providers. Par exemple :
bootstrapApplication(App, {
providers: [
// ... others like provideExperimentalZonelessChangeDetection() ;)
provideHttpClient(),
]
});Si vous utilisez la commande ng update @angular/core (ou Nx) pour mettre votre projet à jour, ce
changement devrait être effectué automatiquement !
Consultez la documentation pour plus d’informations.
Angular.dev devient le site de documentation officiel
Le site, déjà disponible depuis quelques mois, vient officiellement remplacer Angular.io. Ce dernier reste disponible pour l’instant (d’autant qu’il est souvent mieux référencé sur Google) mais devrait prochainement rediriger sur la nouvelle plateforme.
Angular.dev propose de la documentation et des tutoriels interactifs (avec du live coding) ainsi qu’un playground bien pratique.
Sources et liens
Nous avons vu les changements les plus importants de cette nouvelle version, mais il y en a d’autres comme des améliorations du SSR et de l’hydratation de la page. Pour plus d’informations sur ces éléments ou un angle différent sur ceux évoqués dans cet article, n’hésitez pas à consulter les liens suivants :