Développer une application du monde réel avec de multiples appels au serveur peut être plein de bugs. Si vous êtes ici, cela signifie que vous avez lutté avec le retard des appels d’API. Ces retards peuvent causer une UX négative. Aujourd’hui, nous allons comprendre les résolveurs de route dans Angular 8. Il y a plusieurs choses différentes que nous pouvons faire pour améliorer l’expérience utilisateur, comme l’affichage d’un indicateur de progression. Pour rester dans le sujet, voyons ce qu’est un résolveur de route et ce que nous pouvons réaliser avec lui.
Qu’est-ce qu’un résolveur de route Angular ?
Un résolveur est une classe qui implémente l’interface Resolve du routeur Angular. En fait, Resolver est un service qui doit être dans le module racine. Fondamentalement, un Resolver agit comme un middleware, qui peut être exécuté avant le chargement d’un composant.
Vous pouvez également aimer : Résolveurs Angular.
Pourquoi utiliser les résolveurs de route dans Angular?
Pour expliquer comment un résolveur peut être utilisé dans Angular, pensons au scénario où vous utilisez *ngIf="some condition"
, et votre logique repose sur la longueur d’un tableau, qui est manipulé lorsqu’un appel API est terminé. Par exemple, vous pouvez vouloir afficher dans un composant les éléments de ce tableau qui viennent d’être récupérés dans une liste non ordonnée.
<ul><li *ngFor="let item of items">{{item.description}}</li></ul>
Dans cette situation, vous pourriez rencontrer un problème car vos données apparaîtront après que le composant soit prêt. Les éléments du tableau n’existent pas encore réellement. C’est ici que le résolveur de route s’avère pratique. La classe Route Resolver d’Angular récupérera vos données avant que le composant ne soit prêt. Vos déclarations conditionnelles fonctionneront en douceur avec le résolveur.
Interface Resolve
Avant de commencer à mettre en œuvre un résolveur de route, voyons d’abord à quoi ressemble l’interface Resolve.
export interface Resolve<T> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T { return 'Data resolved here...' }}
Si vous voulez créer un résolveur de route, vous devez créer une nouvelle classe qui mettra en œuvre l’interface ci-dessus. Cette interface nous fournit une fonction resolve
, qui vous obtient deux paramètres au cas où vous en auriez besoin. Le premier est la route, qui est de type ActivatedRouteSnapshot
, et le second est l’état, de type RouterStateSnapshot
. Ici, vous pouvez faire un appel API qui obtiendra les données dont vous avez besoin avant que votre composant ne soit chargé.
Via le paramètre route, vous pouvez obtenir des paramètres de route qui peuvent être utilisés dans l’appel API. La méthode resolve
peut retourner un Observable
, une promesse ou simplement un type personnalisé.
Note : Il est important de mentionner que seules les données résolues seront retournées via cette méthode.
C’est une erreur que beaucoup de gens vont faire en utilisant les résolveurs pour la première fois ! Vous devez donc les compléter avant de les envoyer dans le routeur.
Envoyer des données au routeur via un résolveur
Laissez-moi vous montrer ce que je veux dire dans la section ci-dessus. Disons que vous avez une méthode qui renvoie un observable:
items: any = ;getData(): Observable<any> { const observable = Observable.create(observer => { observer.next(this.items) }); return observable;}
Donc, maintenant, vous verrez que l’abonnement que nous avons, ne frappe jamais. Ceci est causé par le fait que vous n’envoyez pas les données correctement. Vous n’avez pas terminé l’abonnement. Pour corriger cette erreur, vous devez compléter l’abonnement en ajoutant une ligne de code supplémentaire.
observer.complete();
Dans le cas où vous retournez une promesse, vous devez la résoudre avant d’envoyer les données au routeur.
Implémentation d’un résolveur de route
Après avoir terminé avec l’explication de base et pourquoi et comment utiliser un résolveur de route, commençons à en implémenter un. Dans ce court exemple, je suppose que vous êtes familier avec les commandes CLI d’Angular et la façon de créer un nouveau projet, donc je vais démontrer seulement le code obligatoire. Vous pouvez trouver le projet de démonstration via le dépôt GitHub à la fin de l’article.
Dans cet exemple, je vais utiliser jsonplaceholder comme une fausse API pour récupérer les données de l’utilisateur afin de démontrer les appels API avec les résolveurs de route.
Tout d’abord, nous aurons besoin d’un service qui ira chercher les données de l’utilisateur pour nous. Dans ce service, nous avons une fonction appelée getUsers()
qui renvoie un observable.
@Injectable({providedIn: 'root'})export class FakeApiService { constructor(private http: HttpClient) { } private usersEndpoint = "https://jsonplaceholder.typicode.com/users"; getUsers(): Observable<any> { // We do not subscribe here! We let the resolver take care of that... return this.http.get(this.usersEndpoint); }}
Il est important de ne pas s’abonner à la fonction getUsers. Le résolveur de route appelé UserResolver s’en chargera pour vous. L’étape suivante consiste à créer un nouveau service appelé UserResolver qui implémentera la fonction resolve de l’interface Resolve du routeur.
@Injectable({providedIn: 'root'})export class UserResolverService implements Resolve<any> { constructor(private fakeApi: FakeApiService) { } resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return this.fakeApi.getUsers().pipe( catchError((error) => { return empty(); }); ); }}
Ce service, UserResolver
, s’abonnera automatiquement à l’observable getUsers
et fournira au routeur les données récupérées. En cas d’erreur, lors de la récupération des données, vous pouvez envoyer un observable vide et le routeur ne procédera pas à la route.
La navigation sera terminée à ce stade. Cette dernière étape consiste à créer un composant qui sera appelé lorsque l’utilisateur ira vers la route /users
. Typiquement, sans Resolver, vous devrez récupérer les données sur le hook ngOnInit
du composant et gérer les erreurs causées par ‘no data’ exists. Le composant de l’utilisateur est simple. Il récupère simplement les données de l’utilisateur dans le ActivatedRoute
et les affiche dans une liste non ordonnée.
Après avoir créé le composant de l’utilisateur, vous devez définir les routes et indiquer au routeur d’utiliser un résolveur ( UserResolver
). Cela pourrait être réalisé avec le code suivant dans le app-routing.modulte.ts
.
const routes: Routes = ;@NgModule({ imports: , exports: })export class AppRoutingModule { }
Vous devez définir la propriété resolve dans la route de l’utilisateur et déclarer le UserResolver
. Les données seront passées dans un objet avec une propriété appelée users. Après cela, vous avez presque terminé. Il ne vous reste plus qu’une chose à faire. Vous devez obtenir les données récupérées dans le composant users via le ActivatedRoute
avec le code suivant.
constructor(private activatedRoute: ActivatedRoute) { }users: any;ngOnInit() { this.activatedRoute.data.subscribe((data: { users: any }) => { this.users = data.users; });}
Puis, vous pouvez juste les afficher dans le HTML sans aucune déclaration *ngIf
( *ngIf="users && users.length > 0
) parce que les données seront là avant que le composant soit chargé.
<h2>Fetched Users:</h2><ul><li *ngFor="let user of users">{{ user.name }}</li></ul>
Summary
Pour clore cet article sur les résolveurs de route, je voudrais souligner une fois de plus les avantages qu’ils nous procurent. Tout d’abord, nous évitons les vérifications ennuyeuses qui doivent être faites au niveau du HTML, de sorte que nous n’avons pas de problèmes jusqu’à ce que nos données soient reçues. Deuxièmement, ils nous permettent de nous concentrer davantage sur l’expérience de l’utilisateur, car nous pouvons arrêter la navigation si une erreur de données survient lors de leur récupération, sans avoir à charger le composant de prévisualisation. Nous pouvons également faire plus avant de terminer la navigation, comme attacher plus de logique ou mapper les données avant d’accéder au composant chargé.
Le code de démonstration est disponible sur GitHub.
Lecture complémentaire
- Tutoriel Angular : Angular 7 et le framework RESTEasy.
- Construire une application Angular 5 étape par étape.
- Application Angular 7 + Spring Boot : Exemple de Hello World.