Imaginez la situation : vous voulez lister la liste des ingrédients de votre recette favoris … et … il est affiché : « aucun ingrédient n’est présent ». Puis quelques secondes plus tard : ça y est vos ingrédients sont là. Frustrant, non ? En tout cas peu ergonomique.
La faute au temps de chargement
Tout est bien fait : vous avez bindé votre template html à votre component. Vous avez bien utilisé RxJs et les Observables.
Oui, mais .. c’est asynchrone. Et le serveur met du temps à charger.
Vive la barre de chargement
Le réflexe ici, qu’on ne voit hélas pas tout le temps sur les applications SPA : ajouter une image de chargement tant que notre liste n’est pas renseignée.
Optimier avec le Resolver
Le resolver est une classe injectable qui va se présenter pour une route. Elle va permettre de précharger les données avant affichage / génération du composant.
Création d’une classe Resolver
(ici nous utilisons ngRx pour le chargement des wookies)
@Injectable()
export class WookieResolver implements Resolve<any> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.store.pipe(
tap(() => {
this.store.dispatch(loadAllWookies());
}),
first()
);
}
}
Référencement dans la partie routing liée
const routes: Routes = [
{
path: '',
component: WookieListComponent,
resolve: {
wookies: WookieResolver
}
},
];
Ajout dans les providers
@NgModule({
declarations: [WookieListComponent],
imports: [
CommonModule,
WookieRoutingModule
],
providers: [
WookieResolver
]
})
export class WookieModule { }
Récupération des éléments dans notre composant
@Component([...])
class WookieComponent implements ngOnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.data.subscribe((data: { wookies: Wookie[] }) => this.wookies = data.wookies);
}
}
On note ici que l’on récupère les wookies qui ont été passés par le Resolver depuis la route.
De plus, le route.data.subscribe nous permet de s’inscrire au changement : donc c’est un comportement réactif !
Faire patienter l’internaute avec un Spinner et le router navigation
Ajout sur le composant parent du spinner
<div *ngIf="pageLoading">
<img src="https://i.pinimg.com/originals/90/80/60/9080607321ab98fa3e70dd24b2513a20.gif">
</div>
Et détection de la navigation
this.router.events.subscribe(event => {
switch(true) {
case event instanceof NavigationStart: {
this.pageLoading = true;
console.info('loading', this.pageLoading);
break;
}
case event instanceof NavigationEnd:
case event instanceof NavigationCancel:
case event instanceof NavigationError: {
console.info('loading', this.pageLoading);
this.pageLoading = false;
break;
}
}
})
Et voilà, nous avons des routes et des composants plus optimisés, qui ne se chargent que lorsque les données sont valides ! 🙂
Happy coding ! 🙂