J'aime l'idée de resolver
s.
Vous pouvez dire ça:
- pour un itinéraire donné, vous vous attendez à ce que certaines données soient chargées en premier
- vous pouvez simplement avoir un composant très simple sans observable (comme récupérer des données depuis this.route.snapshot.data
)
Les résolveurs ont donc beaucoup de sens.
MAIS:
- Vous ne modifiez pas l’URL et n’affichez pas le composant demandé tant que vous n’avez pas reçu la réponse. Donc, vous ne pouvez pas (simplement) montrer à l'utilisateur qu'il se passe quelque chose en rendant votre composant et en en montrant le plus possible (comme il est conseillé de le faire, pour l'application Shell avec PWA). Ce qui signifie qu'en cas de mauvaise connexion, votre utilisateur peut devoir attendre longtemps sans indication visuelle de ce qui se passe.
- Si vous utilisez un résolveur sur une route avec param, prenons comme exemple users/1
, cela fonctionnera correctement la première fois. Mais si vous allez à users/2
, eh bien rien ne se passera si vous ne commencez pas à utiliser un autre observable: this.route.data.subscribe()
Il semble donc que les résolveurs pourraient être utiles pour récupérer des données MAIS en pratique, je ne les utiliserais pas au cas où le réseau serait lent et en particulier pour les routes avec paramètres.
Est-ce que j'ai râté quelque chose? Est-il possible de les utiliser avec ces contraintes réelles?
C'est pourquoi j'utiliserais un résolveur:
myapp.com/lists
, naviguez vers un élément de la liste myapp.com/lists/1
, affichant les détails de cet élément, inutile de récupérer les données, déjà effectuées par la recherche. Supposons ensuite que vous naviguez directement vers myapp.com/lists/1
dont vous avez besoin, puis accédez au composant.Pensez au résolveur en tant que middleware entre votre application et votre composant. Vous pouvez gérer la vue de chargement dans le composant parent, où <router-outlet>
est inclus.
Résolveur: il est exécuté avant même que l'utilisateur ne soit routé vers une nouvelle page.
Lorsque vous avez besoin d'obtenir les données avant l'initialisation du composant, la meilleure façon de le faire consiste à utiliser le résolveur. Le résolveur agit de manière synchrone, c'est-à-dire que le résolveur attendra la fin de l'appel asynchrone et seulement après avoir traité l'appel asynchrone, il sera routé vers l'URL respective. Ainsi, l'initialisation du composant attendra que le rappel soit terminé. Ainsi, si vous voulez faire quelque chose (appel de service), même avant l’initialisation du composant, vous êtes au bon endroit.
Exemple de scénario:Je travaillais sur le projet où l'utilisateur transmettrait le nom du fichier à charger dans l'URL. Sur la base du nom passé, nous ferons l'appel async dans ngOnInit et récupérerons le fichier. Mais le problème avec ceci est, si l'utilisateur passe le nom incorrect dans l'URL, notre service essaiera de récupérer le fichier qui n'existe pas sur le serveur. Nous avons 2 options dans un tel scénario:
Option 1: Pour obtenir la liste des noms de fichiers valides dans ngOnInit, puis appelez le service réel pour récupérer le fichier (si le nom de fichier est valide).Ces deux appels doivent être synchrones.
Option 2: Extrayez la liste des noms de fichiers valides dans le résolveur, vérifiez si le nom de fichier dans l'URL est valide ou non, puis extrayez les données du fichier.
L'option 2 est un meilleur choix, car le résolveur gère la synchronicité des appels.
Important :: Utilisez resolver lorsque vous souhaitez récupérer les données avant même que l'utilisateur ne soit routé vers l'URL. Le résolveur pourrait inclure des appels de service qui nous apporteraient les données nécessaires pour charger la page suivante.
Le résolveur vous donne un crochet au début de la navigation du routeur et vous permet de contrôler la tentative de navigation. Cela vous donne beaucoup de liberté, mais pas beaucoup de règles strictes.
Vous n'êtes pas obligé d'utiliser le résultat de la résolution dans votre composant. Vous pouvez simplement utiliser la résolution comme un crochet. C'est ma façon préférée de l'utiliser pour les raisons que vous avez citées. L'utilisation du résultat dans votre composant est beaucoup plus simple, mais il existe des compromis synchrones.
Par exemple, si vous utilisez quelque chose comme Material ou Cdk, vous pouvez envoyer une boîte de dialogue de "chargement" pour afficher un indicateur de progression au début de la résolution, puis fermer la boîte de dialogue lorsque la résolution est terminée. Ainsi:
constructor(route: ActivatedRouteSnapshot, myService: MyService, dialog: MatDialog) {}
resolve() {
const dialogRef = this.dialog.open(ProgressComponent);
return this.myService.getMyImportantData().pipe(
tap(data => this.myService.storeData(data)),
tap(() => dialogRef.close()),
map(() => true),
catchError(err => of(false))
);
}
Si vous utilisez ngrx
, vous pouvez faire quelque chose de similaire en distribuant des actions pendant que la résolution est en cours.
Lorsque vous utilisez la protection Resolve de cette manière, il n'y a pas de raison particulièrement forte d'utiliser la protection Resolve au lieu de la protection CanActivate. Ce choix revient à la sémantique. Je trouve plus évident de mettre en place l'authentification sur CanActivate et de lancer la récupération des données à partir de Resolve. Lorsque ces sujets sont autorisés à se mélanger, cela devient un choix abstrait.