Mise à jour le 13/07/2018 : Refonte complète du code pour utiliser des conventions plus récentes. Mise à niveau d’Angular et de RxJS vers les dernières versions disponibles, déplacement des exemples vers StackBlitz.
Le but de ce post est de démontrer comment les routes resolves Angular fonctionnent en 10 minutes, en même temps que de fournir des exemples de code sur Stackblitz. Si vous êtes déjà familier avec les routes resolves d’AngularJS, je recommande de sauter l’intro et de passer directement à la section de l’application exemple.
Table des matières
Intro
Application exemple
- Étape 1 : Créer une classe de résolveur
- Étape 2 : Ajouter une garde de résolution à la route
- Étape 3 : Obtenir les données résolues à partir de la route activée du composant
Notes & Conseils
- Éviter les appels d’API redondants
- Multiples résolutions sur la la même route
- Passer les paramètres de la route au résolveur
Notes de clôture
Intro
Les résolutions de route ne sont rien d’autre qu’un moyen de prérécupérer les données dont un composant a besoin avant son initialisation. Généralement, ces données proviennent d’une API. Disons que vous avez un composant dont le seul rôle est d’afficher un graphique des ventes quotidiennes pour le mois ; Il n’y a aucun intérêt à rendre la vue ou à charger ce composant avant que les données de ventes soient disponibles. En fait, de nombreuses bibliothèques de graphiques produiront une erreur si vous essayez d’initialiser un graphique avant de lui fournir des données (et il en sera de même pour *ngFor
). Bien sûr, vous pouvez facilement contourner ce problème en masquant le html avec un *ngIf
ou en fournissant temporairement un tableau vide jusqu’à ce que les données nécessaires soient chargées. Cependant, bien que vous puissiez vous en sortir sans résoudre, leur mise en œuvre aide à rendre le code plus lisible et maintenable en :
- Éliminant le fouillis confus dans le modèle et le code de votre composant.
- Clarifiant votre intention en montrant quelles données doivent être pré-recherchées.
Malgré ces avantages, de nombreux sites évitent d’utiliser les résolus en faveur de l’affichage de la majeure partie du composant et de l’affichage d’un spinner dans les sections pour lesquelles les données sont encore en cours de chargement. Dans certains cas, cette approche est souhaitable d’un point de vue UX, et une résolution ne devrait pas être utilisée. Utilisez votre discrétion.
Application type
Ouvrir l’application type
Comme vous pouvez le voir, notre point de départ est une application très basique avec deux routes – « Accueil » et « Nouvelles ». Vous naviguez entre les routes en cliquant sur l’onglet correspondant. Nous allons ajouter une résolution pour récupérer au préalable les actualités à partir d’une API avant le chargement du composant Actualités. Cela se fera en trois étapes :
Etape 1 : Créer une classe resolver qui fait un appel Http pour pré-recueillir les données dont nous avons besoin.
Créer un nouveau fichier Typescript à l’intérieur du dossier app
et le nommer:
news-resolver.service.ts
Puis copier et coller le code suivant dans votre nouveau fichier (expliqué ci-dessous):
Décomposons ce que nous avons fait dans le code ci-dessus:
-
Ajouté des déclarations d’importation ES6 pour apporter les modules nécessaires.
-
Créé une nouvelle classe TypeScript
NewsResolver
. -
Ajouté l’interface
Resolve
à notre classe – c’est OPTIONNEL, mais toute classe que nous prévoyons d’utiliser comme résolveur doit implémenter une méthode resolve, donc c’est une bonne convention. -
Ajouté une méthode
resolve()
àNewsResolver
– c’est la méthode responsable du retour des données dont nous avons besoin. Nommer la méthode qui renvoie les données pour une garde de résolution « resolve » n’est PAS facultatif – le résolveur ne fonctionnerait pas si la méthode était nommée autrement. -
Si vous avez remarqué qu’une requête
POST
est incorrectement utilisée au lieu d’uneGET
dans le code ci-dessus, vous avez tout à fait raison ; Dans une application réelle, ce serait une requêteGET
. Les exemples ici tirent profit de, qui est un site fournissant des endpoints API de test.
Avant de continuer, nous devons inclure la classe resolver que nous venons de créer dans notre module de routage. Naviguez vers app-routing.module.ts
et ajoutez NewsResolver
au tableau providers
. Ou, si vous commencez tout juste à travailler avec Angular 2, remplacez simplement le contenu de app-routing.module.ts
par le code ci-dessous – les changements sont marqués par des notes :
Avec cela fait, nous avons maintenant défini la classe resolver. Dans les étapes suivantes, nous l’ajouterons à notre route.
Code après l’ajout de la classe de résolveur
Étape 2 : Ajouter une garde de résolution à la route.
Dans app-routing.module.ts
, changez la ligne de code suivante { path: 'news', component: NewsComponent }
en:
{ path: 'news', component: NewsComponent, resolve: { news: NewsResolver }}
Tout ce que nous avons fait ici est d’ajouter la garde de résolution que nous venons de définir à notre route news
. Cela indique à Angular que nous devons attendre que la méthode resolve()
de NewsResolver
renvoie des données avant d’afficher le NewsComponent
.
Il est important de souligner que news
dans la ligne news: NewsResolver
de code est ce que j’ai choisi pour nommer les données, quelles qu’elles soient, renvoyées par le résolveur. Vous pouvez le nommer comme vous voulez.
Comme une note un peu tangentielle – si vous n’êtes pas familier avec les gardes de route Angular en général, et que vous souhaitez en savoir plus, la documentation est ici. Entrer dans les détails des gardes est en dehors de la portée de ce post, mais vous devez savoir qu’il y a d’autres gardes que resolve
disponibles, ce qui est la raison pour laquelle j’ai évoqué ce terme.
Code avec la garde Resolve ajoutée
Étape 3 : Obtenir les données résolues à partir de la route activée du composant.
Maintenant que nous avons une classe de résolveur et que nous l’avons ajoutée à notre route, les données sont en train d’être prélevées. L’étape finale consiste à accéder aux données prétirées dans notre NewsComponent
situé dans app/news.component.ts
. Naviguez vers ce fichier et ajoutez le module ES6 suivant:
import { ActivatedRoute } from '@angular/router';
puis fournissez ActivatedRoute
dans le constructeur du composant News en ajoutant le code suivant en haut de la définition de la classe NewsComponent
:
constructor(private route: ActivatedRoute) {}
Comme vous le savez, ou l’avez peut-être deviné, ActivatedRoute
nous permet d’accéder aux informations sur la route qui est actuellement active, comme l’url de la route, les paramètres de requête, etc. Ce qui nous intéresse ici, ce sont les données de nouvelles qui sont chargées dans le ActivatedRoute
à partir de la garde resolve. Pour obtenir les données de nouvelles résolues de la route, ajoutez une propriété pour contenir les données de nouvelles:
public news: any;
et ensuite obtenez les données de la route activée lorsque le NewsComponent
est initialisé:
ngOnInit(): void { this.news = this.route.snapshot.data; }
C’est pratiquement tout. Modifiez le modèle de composant de nouvelles pour afficher les nouvelles de la route résolue en supprimant le contenu actuel:
<div>This is just a placeholder for now. News will go here. </div>
et en le remplaçant par:
Vous devriez maintenant être accueilli avec les dernières nouvelles, « Le ciel est bleu », lorsque vous cliquez sur l’onglet Nouvelles.
Code terminé
Notes &Conseils
– Les résolutions peuvent provoquer des appels d’API redondants : Un resolve obtient des données à chaque fois qu’un composant est chargé. Cela entraîne souvent des appels d’API inutiles qui nuisent aux performances. Si votre resolve obtient des données qui ne changent pas fréquemment, envisagez d’écrire les données retournées par le resolve dans une propriété de la classe du resolver et de simplement retourner cette propriété si elle a déjà été définie. Par exemple, dans notre exemple, nous ajouterions une propriété news
initialement non définie comme suit : public news: any = undefined;
dans notre résolveur de nouvelles. Ensuite, dans la méthode resolve()
, on vérifie si la propriété news
est déjà définie et on renvoie sa valeur sans faire d’appel à l’API si c’est le cas, c’est-à-dire :
resolve(): Observable<any> { if (this.news) { return this.getSavedNews(); } else { return this.getNewsFromApi() } }
Exemple de code complet ci-dessous. Si la syntaxe des observables vous semble un peu inhabituelle, c’est parce que j’utilise RxJS 6
. Il y a un bon tutoriel sur les changements récemment introduits dans RxJS
ici si vous avez besoin d’un rafraîchissement.
Retourner les données sauvegardées, si elles ont déjà été récupérées de l’API
Naturellement, vous pourriez aller plus loin et définir une période de temps pendant laquelle les données sont valides en ne sauvegardant pas seulement les données, mais en ajoutant une autre propriété d’horodatage et en faisant un appel à l’API si les données sont plus anciennes que x.
– Tout comme dans AngularJS, vous pouvez utiliser plusieurs résolus sur la même route. Les appels de résolution sont effectués en parallèle et le composant ne se chargera que lorsque tous les appels auront renvoyé des données. Pour utiliser plusieurs résolus, il suffit de les ajouter à la route:
Puis des données de résolution supplémentaires peuvent être accédées à partir du snapshot de la route tout comme un seul résolu:
ngOnInit(): void { this.news = this.route.snapshot.data; this.alternativeNews = this.route.snapshot.data; }
Code avec plusieurs résolus
– Le résolveur a accès aux paramètres de la route. Disons que vous avez un composant qui affiche une liste de titres de nouvelles. Lorsqu’on clique sur un article, un autre composant, qui affiche l’article complet, s’ouvre. Avant de charger ce composant, nous devons récupérer au préalable le contenu de l’article d’actualité dont le titre a été cliqué – cette opération peut être effectuée par la méthode resolve. La classe resolver a accès au ActivatedRoute
, donc nous pouvons obtenir l’id de l’article qui a été cliqué:
resolve(route: ActivatedRouteSnapshot) { let id: any = route.params); return this.getNewsStory(id); }
C’est assez explicite. Pour un exemple, regardez le nouveau fichier src/news-story-resolver.service.ts
dans le lien ci-dessous. Les liens vers le nouveau composant ont été ajoutés dans l’onglet Nouvelles (news.component.ts
).
Code avec résolution paramétrée
.