Understanding Angular Route Resolvers

winding-road-between-forest

Die Entwicklung einer realen Anwendung mit mehreren Aufrufen zum Server kann voller Bugs sein. Wenn Sie hier sind, bedeutet das, dass Sie mit der Verzögerung von API-Aufrufen zu kämpfen haben. Diese Verzögerungen können eine negative UX verursachen. Heute werden wir Route Resolver in Angular 8 verstehen. Es gibt verschiedene Dinge, die wir tun können, um die Benutzererfahrung zu verbessern, wie z. B. die Anzeige einer Fortschrittsanzeige. Um beim Thema zu bleiben, sehen wir uns an, was ein Route Resolver ist und was wir damit erreichen können.

Was ist ein Angular Route Resolver?

Ein Resolver ist eine Klasse, die das Resolve-Interface von Angular Router implementiert. Tatsächlich ist der Resolver ein Service, der im Root-Modul liegen muss. Im Grunde agiert ein Resolver wie eine Middleware, die ausgeführt werden kann, bevor eine Komponente geladen wird.

You may also like: Angular Resolver.

Warum verwendet man Route Resolver in Angular?

Um zu erklären, wie ein Resolver in Angular verwendet werden kann, lassen Sie uns über das Szenario nachdenken, wenn Sie *ngIf="some condition" verwenden und Ihre Logik auf der Länge eines Arrays beruht, das manipuliert wird, wenn ein API-Aufruf abgeschlossen ist. Sie möchten zum Beispiel in einer Komponente die Elemente dieses Arrays anzeigen, die gerade in einer ungeordneten Liste geholt wurden.

<ul><li *ngFor="let item of items">{{item.description}}</li></ul>

In dieser Situation könnten Sie ein Problem bekommen, weil Ihre Daten erst erscheinen, wenn die Komponente fertig ist. Die Elemente im Array sind noch nicht wirklich vorhanden. Hier kommt der Route Resolver ins Spiel. Die Klasse Route Resolver von Angular holt Ihre Daten ab, bevor die Komponente fertig ist. Ihre bedingten Anweisungen werden mit dem Resolver reibungslos funktionieren.

Resolve Interface

Bevor wir mit der Implementierung eines Route Resolvers beginnen, lassen Sie uns zunächst sehen, wie das Resolve Interface aussieht.

export interface Resolve<T> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T { return 'Data resolved here...' }}

Wenn Sie einen Route Resolver erstellen wollen, müssen Sie eine neue Klasse erstellen, die das oben genannte Interface implementiert. Diese Schnittstelle stellt uns eine resolve Funktion zur Verfügung, die Ihnen zwei Parameter liefert, falls Sie diese benötigen. Der erste ist die Route, die vom Typ ActivatedRouteSnapshot ist, und der zweite ist der Status, vom Typ RouterStateSnapshot. Hier können Sie einen API-Aufruf tätigen, der die benötigten Daten abruft, bevor Ihre Komponente geladen wird.

Über den Parameter route können Sie Routenparameter abrufen, die in dem API-Aufruf verwendet werden können. Die resolveMethode kann ein Observable, ein Versprechen oder einfach einen benutzerdefinierten Typ zurückgeben.

Hinweis: Es ist wichtig zu erwähnen, dass nur aufgelöste Daten über diese Methode zurückgegeben werden.

Dies ist ein Fehler, den viele Leute machen, wenn sie Resolver zum ersten Mal verwenden! Sie müssen sie also vervollständigen, bevor Sie sie an den Router senden.

Daten über einen Resolver an den Router senden

Lassen Sie mich Ihnen zeigen, was ich im obigen Abschnitt meine. Nehmen wir an, Sie haben eine Methode, die ein Observable zurückgibt:

items: any = ;getData(): Observable<any> { const observable = Observable.create(observer => { observer.next(this.items) }); return observable;}

So, jetzt werden Sie sehen, dass das Abonnement, das wir haben, nie eintrifft. Das liegt daran, dass Sie die Daten nicht korrekt senden. Sie haben das Abonnement nicht abgeschlossen. Um diesen Fehler zu beheben, müssen Sie das Abonnement vervollständigen, indem Sie eine weitere Codezeile hinzufügen.

observer.complete();

Wenn Sie ein Versprechen zurückgeben, müssen Sie es auflösen, bevor Sie die Daten an den Router senden.

Implementierung eines Route Resolvers

Nachdem wir die Grundlagen erklärt haben und warum und wie man einen Route Resolver verwendet, lassen Sie uns mit der Implementierung eines solchen beginnen. In diesem kurzen Beispiel gehe ich davon aus, dass Sie mit den CLI-Befehlen von Angular vertraut sind und wissen, wie man ein neues Projekt erstellt, daher werde ich nur den obligatorischen Code demonstrieren. Das Demoprojekt finden Sie über das GitHub-Repository am Ende des Artikels.

In diesem Beispiel werde ich jsonplaceholder als Fake-API verwenden, um Benutzerdaten zu holen und API-Aufrufe mit Route-Resolvern zu demonstrieren.

Zuallererst benötigen wir einen Dienst, der die Benutzerdaten für uns abruft. In diesem Dienst haben wir eine Funktion namens getUsers(), die ein Observable zurückgibt.

@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); }}

Es ist wichtig, dass wir die Funktion getUsers nicht abonnieren. Der Routenauflöser namens UserResolver wird sich darum kümmern. Der nächste Schritt besteht darin, einen neuen Dienst namens UserResolver zu erstellen, der die Resolve-Funktion der Resolve-Schnittstelle des Routers implementiert.

@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(); }); ); }}

Dieser Dienst, UserResolver, wird automatisch das getUsers Observable abonnieren und dem Router die abgerufenen Daten zur Verfügung stellen. Im Falle eines Fehlers beim Abrufen der Daten kann ein leeres Observable gesendet werden, und der Router fährt nicht mit der Route fort.

Die Navigation wird an dieser Stelle abgebrochen. Der letzte Schritt besteht darin, eine Komponente zu erstellen, die aufgerufen wird, wenn der Benutzer zur /users-Route geht. Ohne einen Resolver müssen Sie normalerweise die Daten über den ngOnInit-Hook der Komponente abrufen und die Fehler behandeln, die durch das Vorhandensein „keiner Daten“ verursacht werden. Die Komponente des Benutzers ist eine einfache Komponente. Sie holt nur die Daten des Benutzers aus dem ActivatedRoute und zeigt sie in einer ungeordneten Liste an.

Nachdem Sie die Benutzerkomponente erstellt haben, müssen Sie die Routen definieren und dem Router sagen, dass er einen Resolver verwenden soll ( UserResolver). Dies kann mit folgendem Code in der app-routing.modulte.ts.

const routes: Routes = ;@NgModule({ imports: , exports: })export class AppRoutingModule { }

Sie müssen die resolve-Eigenschaft in der Benutzerroute festlegen und die UserResolver deklarieren. Die Daten werden an ein Objekt mit einer Eigenschaft namens users übergeben. Danach sind Sie fast fertig. Es gibt nur noch eine Sache, die Sie tun müssen. Sie müssen die abgerufenen Daten über die ActivatedRoute mit folgendem Code in die Users-Komponente bringen.

constructor(private activatedRoute: ActivatedRoute) { }users: any;ngOnInit() { this.activatedRoute.data.subscribe((data: { users: any }) => { this.users = data.users; });}

Danach können Sie sie einfach in HTML ohne *ngIf-Anweisungen ( *ngIf="users && users.length > 0 ) anzeigen, da die Daten dort vorhanden sind, bevor die Komponente geladen wird.

<h2>Fetched Users:</h2><ul><li *ngFor="let user of users">{{ user.name }}</li></ul>

Zusammenfassung

Zum Abschluss dieses Artikels über Route Resolver möchte ich noch einmal auf die Vorteile hinweisen, die sie uns bieten. Erstens vermeiden wir die lästigen Prüfungen, die auf HTML-Ebene durchgeführt werden müssen, so dass wir keine Probleme haben, bis unsere Daten empfangen werden. Zweitens können wir uns mehr auf das Benutzererlebnis konzentrieren, da wir die Navigation unterbrechen können, wenn beim Abrufen der Daten ein Fehler auftritt, ohne die Vorschaukomponente laden zu müssen. Wir können auch mehr tun, bevor wir die Navigation abschließen, z. B. weitere Logik anhängen oder die Daten zuordnen, bevor wir auf die geladene Komponente zugreifen.

Der Demo-Code ist auf GitHub verfügbar.

Weiteres Lesen

  • Angular Tutorial: Angular 7 and the RESTEasy Framework.
  • Building an Angular 5 Application Step-By-Step.
  • Angular 7 + Spring Boot Application: Hello World Beispiel.

Schreibe einen Kommentar