Comment créer un indicateur de chargement réutilisable pour les projets angulaires

Réutilisabilité . Un mot qui m'a traversé l'esprit plusieurs fois récemment, alors que je travaillais sur un projet Angular. J'ai décidé de créer mes propres réutilisables Angular et mon blog sur l'expérience.

Alors, qu'est-ce qu'un indicateur de chargement? Habituellement, il s'agit d'une sorte de spinner avec une superposition, ce qui empêche les interactions de l'utilisateur. L'interface utilisateur n'est pas cliquable et le focus est intercepté. Par conséquent, l'utilisateur ne peut pas modifier accidentellement les données ou l'état de l'application en interagissant avec les entrées derrière la superposition.

Une fois le chargement arrêté, la superposition avec la double flèche est supprimée du DOM et l'élément précédemment focalisé est à nouveau focalisé.

J'ai commencé avec la logique qui déclencherait le spinner. Pour cela, j'ai utilisé un simple BehaviorSubject et deux fonctions de décorateur:

import {BehaviorSubject} from 'rxjs'; import {distinctUntilChanged} from 'rxjs/operators'; const indicatorSubject = new BehaviorSubject(false); export const isLoading$ = indicatorSubject.asObservable().pipe(distinctUntilChanged()); export function startLoadingIndicator(target: any, propertyKey: string | symbol, propertyDescriptor: PropertyDescriptor): any { const original = propertyDescriptor.value; propertyDescriptor.value = (...args) => { indicatorSubject.next(true); const result = original.call(target, ...args); return result; }; return propertyDescriptor; } export function stopLoadingIndicator(target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor): any { const original = propertyDescriptor.value; propertyDescriptor.value = (...args) => { indicatorSubject.next(false); const result = original.call(target, ...args); return result; }; return propertyDescriptor; } 

De cette façon, nous n'avons pas besoin d'un service injectable pour déclencher ou arrêter le spinner. Les deux méthodes simples de décorateur appellent simplement .next () sur notre BehaviorSubject. La variable isLoading $ est exportée en tant qu'observable.

Utilisons-le dans notre composant indicateur de chargement.

get isLoading$(): Observable { return isLoading$; }

Maintenant, dans votre modèle, vous pouvez utiliser votre getter isLoading $ avec le tube asynchrone pour afficher / masquer toute la superposition.

Comme vous pouvez le voir, j'ai extrait le spinner dans son propre composant, et j'ai fait plusieurs autres choses. J'ai ajouté une logique pour le piégeage du focus et la possibilité de configurer la taille et la couleur du spinner à l'aide d'un InjectionToken.

import {LoadingIndicatorConfig} from './interfaces/loading-indicator.interfaces'; import {InjectionToken} from '@angular/core'; export const DEFAULT_CONFIG: LoadingIndicatorConfig = { size: 160, color: '#7B1FA2' }; export const LOADING_INDICATOR_CONFIG: InjectionToken = new InjectionToken('btp-li-conf'); 

Fournir des objets de configuration à l'aide d'InjectionToken est un bon moyen de fournir des propriétés configurables dans le constructeur.

 constructor(@Inject(LOADING_INDICATOR_CONFIG) private config: LoadingIndicatorConfig) { }

Maintenant, nous devons tout regrouper dans un NgModule:

import {ModuleWithProviders, NgModule} from '@angular/core'; import {LoadingIndicatorComponent} from './loading-indicator/loading-indicator.component'; import {CommonModule} from '@angular/common'; import {SpinnerComponent} from './spinner/spinner.component'; import {DEFAULT_CONFIG, LOADING_INDICATOR_CONFIG} from './loading-indicator.config'; @NgModule({ declarations: [LoadingIndicatorComponent, SpinnerComponent], imports: [ CommonModule ], exports: [LoadingIndicatorComponent] }) export class LoadingIndicatorModule { static forRoot(): ModuleWithProviders { return { ngModule: LoadingIndicatorModule, providers: [{provide: LOADING_INDICATOR_CONFIG, useValue: DEFAULT_CONFIG}] }; } }

Après avoir construit la bibliothèque et l'avoir installée dans une application angulaire, le déclenchement du spinner devient extrêmement facile en utilisant les deux méthodes de décorateur.

Tout d'abord, nous devons ajouter le composant au bon endroit dans le DOM. Je le mets généralement dans le composant d'entrée de l'application, au bas du modèle.

Loading indicator

START LOADING

Comme vous pouvez le voir, la méthode triggerLoadingIndicator est appelée lorsque l'utilisateur clique sur le bouton. Cette méthode est une méthode décorée:

 @startLoadingIndicator triggerLoadingIndicator() { setTimeout(this.triggerLoadingIndicatorStop.bind(this), 500); } @stopLoadingIndicator triggerLoadingIndicatorStop() { console.log('stopped'); }

Et c'est tout. Bien sûr, dans une application réelle, on pourrait l'utiliser pour décorer les requêtes et leurs gestionnaires de réponses respectifs. Un petit conseil: décorez également vos gestionnaires d'erreurs. :)

Merci beaucoup d'avoir lu ce billet de blog. Si vous souhaitez essayer la librairie mentionnée ci-dessus, vous pouvez trouver le paquet et les instructions pour l'installer ici.

Vous pouvez également me suivre sur Twitter ou GitHub.