Appearance
Utiliser des paramètres dans le routeur
Il est possible de passer des paramètres dans l'URL pour afficher des informations spécifiques. Par exemple, pour afficher le profil d'un utilisateur, nous pouvons passer l'identifiant de l'utilisateur dans l'URL. Avant tout, voici la structure de notre application :
plaintext
app/
|- app.component.ts
|- app.router.ts
|- app.config.ts
|- main.component.ts
|- other.component.ts
ts
import { Routes } from '@angular/router';
import {OtherComponent} from './other.component';
import {MainComponent} from './main.component';
export const routes: Routes = [
{ path: '', redirectTo: 'main', pathMatch: 'full' },
{ path: 'main', component: MainComponent },
{ path: 'other/:id', component: OtherComponent }
];
:id
indique que nous pouvons avoir un identifiant.
Naviguer avec un paramètre
ts
import {Component} from '@angular/core';
import {RouterOutlet, RouterLink} from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet, RouterLink],
standalone: true,
template: `
<ul>
<li><a [routerLink]="['/main']">main</a></li>
<li><a [routerLink]="['/other', 1337]">other</a></li>
</ul>
<router-outlet></router-outlet>
`
})
export class AppComponent {}
Nous avons deux liens, un pour main
et un pour other
. Le lien other
a un paramètre 1337
. Nous utilisons un tableau pour définir le lien. Pourquoi ? Il est plus simple de passer des paramètres avec un tableau que de manipuler des chaînes.
Récupérer le paramètre dans le composant
Admettons que nous avons un composant OtherComponent
:
js
import { Component, OnInit, inject } from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-other',
standalone: true,
template: `
Other with id {{id}}
<button (click)="nav()">MainComponent</button>
`
})
export class OtherComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
id = 0;
ngOnInit() {
this.route.params.subscribe(params => {
this.id = +params.id; // + permet de convertir la chaîne en nombre
});
}
nav() {
this.router.navigate(['/main']);
}
}
Nous chargeons et initialisons le service ActivatedRoute
. Nous récupérons le paramètre avec un Observable lorsque le composant est initialisé.
Pourquoi avoir utiliser uj observable ?
Les paramètres de route sont des observables. Cela signifie que nous pouvons les observer pour obtenir les valeurs. Cela nous permet de réagir aux changements de paramètres. Et ça peut être le cas ici ! Si nous changeons l'identifiant dans l'URL, le composant OtherComponent
sera mis à jour.
Utiliser snapshot pour une valeur unique
Si vous n'avez pas besoin de réagir aux changements de paramètres, vous pouvez utiliser snapshot
pour récupérer la valeur actuelle du paramètre :
ts
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-other',
standalone: true,
template: `
Other with id {{id}}
`
})
export class OtherComponent {
private route = inject(ActivatedRoute);
id = this.route.snapshot.params['id'];
}
ATTENTION
snapshot
ne réagira pas aux changements de paramètres. Si votre composant peut être réutilisé avec des paramètres différents (par exemple, naviguer de /user/1 vers /user/2), utilisez plutôt l'observable params
comme montré précédemment.
CONSEIL
Utilisez snapshot
quand :
- Vous êtes certain que les paramètres ne changeront pas pendant la durée de vie du composant
- Vous voulez une syntaxe plus simple et directe
- Vous n'avez pas besoin de réagir aux changements de paramètres
Utiliser queryParamMap pour les paramètres de requête
Les paramètres de requête sont différents des paramètres de route. Ils apparaissent après le ?
dans l'URL et permettent de filtrer ou trier des données sans changer de page. Par exemple : /users?sort=name&order=asc
.
Imaginons que nous voulons afficher une liste d'utilisateurs avec la possibilité de les filtrer et de les trier :
ts
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from '../../core/services/user.service';
import { User } from './user.interface';
@Component({
selector: 'app-user-list',
standalone: true,
template: `
<div class="filters">
<select (change)="onSort($event)">
<option value="name">Trier par nom</option>
<option value="email">Trier par email</option>
</select>
<input
type="text"
[value]="searchTerm"
(input)="onSearch($event)"
placeholder="Rechercher..."
>
</div>
@for (user of users; track user.id) {
<div class="user-card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</div>
}
`
})
export class UserListComponent implements OnInit {
private route = inject(ActivatedRoute);
private router = inject(Router);
private userService = inject(UserService);
users: User[] = [];
searchTerm = '';
sortBy = 'name';
ngOnInit() {
// Observer les changements des paramètres de requête
this.route.queryParamMap.subscribe(params => {
this.searchTerm = params.get('search') || '';
this.sortBy = params.get('sort') || 'name';
this.loadUsers();
});
}
onSearch(event: Event) {
const value = (event.target as HTMLInputElement).value;
this.updateQueryParams({ search: value });
}
onSort(event: Event) {
const value = (event.target as HTMLSelectElement).value;
this.updateQueryParams({ sort: value });
}
private updateQueryParams(params: { [key: string]: string }) {
this.router.navigate([], {
relativeTo: this.route,
queryParams: params,
queryParamsHandling: 'merge' // Garde les autres paramètres existants
});
}
private loadUsers() {
this.userService.getUsers({
search: this.searchTerm,
sort: this.sortBy
}).subscribe(users => this.users = users);
}
}
Analysons cette syntaxe de navigation :
typescript
this.router.navigate([], {
relativeTo: this.route,
queryParams: params,
queryParamsHandling: 'merge'
});
Décomposons chaque partie :
navigate([])
: Le tableau vide[]
signifie que nous ne changeons pas de route, nous restons sur la même pagerelativeTo: this.route
: Indique que nous voulons naviguer relativement à la route actuellequeryParams: params
: Définit les nouveaux paramètres de requête à ajouter dans l'URLqueryParamsHandling: 'merge'
: Détermine comment gérer les paramètres existants
Exemple concret
Imaginons que nous sommes sur l'URL : /users?page=1&sort=name
Si nous exécutons :
typescript
this.router.navigate([], {
relativeTo: this.route,
queryParams: { search: 'john' },
queryParamsHandling: 'merge'
});
L'URL deviendra : /users?page=1&sort=name&search=john
Sans merge
, nous aurions perdu page
et sort
: /users?search=john
ATTENTION
Si vous omettez queryParamsHandling
, tous les paramètres de requête existants seront supprimés et remplacés par les nouveaux. Utilisez 'merge'
si vous voulez conserver les autres filtres actifs.
Avantages des Query Params
Les query params sont parfaits pour :
- Filtrer des données
- Trier des résultats
- Gérer la pagination
- Sauvegarder l'état de l'interface utilisateur
- Partager des URLs avec des filtres spécifiques
Utiliser snapshot avec queryParamMap
Comme pour les params normaux, vous pouvez aussi utiliser snapshot pour les queryParams si vous n'avez pas besoin de réagir aux changements :
ts
export class SimpleUserListComponent {
private route = inject(ActivatedRoute);
// Récupération unique des query params
searchTerm = this.route.snapshot.queryParamMap.get('search') || '';
sortBy = this.route.snapshot.queryParamMap.get('sort') || 'name';
}
Préserver les queryParams lors de la navigation
Parfois, vous voulez garder les queryParams lors de la navigation vers une autre route. Vous pouvez le faire de deux façons :
ts
// Dans le template avec routerLink
<a [routerLink]="['/other-page']" [queryParamsHandling]="'preserve'">Autre page</a>
// Dans le component avec Router
this.router.navigate(['/other-page'], {
queryParamsHandling: 'preserve'
});
Les options pour queryParamsHandling
sont :
'preserve'
: garde tous les queryParams actuels'merge'
: fusionne les nouveaux queryParams avec les existants