Angular Route risolve in 10 minuti

Aggiornato il 13/07/2018: Ampia revisione del codice per utilizzare convenzioni più recenti. Aggiornato Angular e RxJS alle ultime versioni disponibili, spostato esempi su StackBlitz.

L’obiettivo di questo post è dimostrare come funzionano le route resolves di Angular in 10 minuti, insieme a fornire codice di esempio su Stackblitz. Se hai già familiarità con le route resolves di AngularJS, ti consiglio di saltare l’introduzione e saltare direttamente alla sezione dell’app di esempio.

Tabella dei contenuti

Intro
App di esempio

  • Step 1: Creare una classe Resolver
  • Step 2: Aggiungere un Resolve Guard alla rotta
  • Step 3: Ottenere i dati risolti dalla rotta attivata del componente

Note & Suggerimenti

  • Evitare le chiamate API ridondanti
  • Multiple risoluzioni sulla sulla stessa rotta
  • Passare i parametri della rotta al risolutore

Note conclusive

Intro

Le risoluzioni delle rotte non sono altro che un modo per prerecuperare i dati di cui un componente ha bisogno prima di essere inizializzato. Di solito questi dati provengono da un’API. Diciamo che avete un componente il cui unico ruolo è quello di visualizzare un grafico delle vendite giornaliere per il mese; non ha senso rendere la vista o caricare questo componente prima che i dati delle vendite siano disponibili. Infatti, molte librerie di grafici daranno un errore se cercate di inizializzare un grafico prima di fornirgli i dati (e così farà *ngFor). Naturalmente, potete facilmente aggirare questo problema nascondendo l’html con un *ngIf o fornendo temporaneamente un array vuoto fino a quando i dati necessari sono caricati. Tuttavia, anche se si può fare a meno delle risoluzioni, implementarle aiuta a rendere il codice più leggibile e manutenibile:

  1. Eliminando il disordine confuso nel template e nel codice del vostro componente.
  2. Chiarisci il tuo intento mostrando quali dati devono essere pre-caricati.

Nonostante questi benefici, molti siti evitano di usare le risoluzioni in favore della visualizzazione della maggior parte del componente e mostrano uno spinner nelle sezioni in cui i dati sono ancora in fase di caricamento. In alcuni casi, questo approccio è desiderabile da un punto di vista UX, e una risoluzione non dovrebbe essere usata. Usa la tua discrezione.

Sample App

Open Sample App

Come puoi vedere, il nostro punto di partenza è un’app molto semplice con due percorsi – “Home” e “News”. Si naviga tra i percorsi cliccando sulla scheda corrispondente. Stiamo per aggiungere un resolve per pre-fetchare le notizie da un’API prima che il componente News venga caricato. Questo richiederà tre passi:

Passo 1: Creare una classe resolver che faccia una chiamata Http per pre-fetchare i dati di cui abbiamo bisogno.

Crea un nuovo file Typescript all’interno della cartella app e nominalo:

news-resolver.service.ts

Poi copia e incolla il seguente codice nel tuo nuovo file (spiegato di seguito):

Ripercorriamo quello che abbiamo fatto nel codice precedente:

  • Aggiunte dichiarazioni di importazione ES6 per portare i moduli necessari.

  • Creato una nuova classe TypeScript NewsResolver.

  • Aggiunto l’interfaccia Resolve alla nostra classe – questo è FACOLTATIVO, ma ogni classe che abbiamo intenzione di usare come resolver deve implementare un metodo resolve, quindi è una buona convenzione.

  • Aggiunto un metodo resolve() a NewsResolver – questo è il metodo responsabile della restituzione dei dati di cui abbiamo bisogno. Chiamare il metodo che restituisce i dati per una guardia “resolve” NON è opzionale – il resolver non funzionerebbe se il metodo fosse chiamato in altro modo.

  • Se hai notato che nel codice sopra è stata erroneamente usata una richiesta POST invece di una GET, hai assolutamente ragione; in una vera applicazione, questa sarebbe una richiesta GET. Gli esempi qui sfruttano , che è un sito che fornisce endpoint API di prova.

Prima di andare avanti, dobbiamo includere la classe resolver che abbiamo appena creato nel nostro modulo di routing. Navigate fino a app-routing.module.ts e aggiungete NewsResolver all’array providers. Oppure, se hai appena iniziato a lavorare con Angular 2, sostituisci semplicemente il contenuto di app-routing.module.ts con il codice qui sotto – le modifiche sono contrassegnate da note:

Con questo fatto, abbiamo ora definito la classe resolver. Nei passi seguenti, la aggiungeremo alla nostra rotta.

Codice dopo aver aggiunto la classe resolver

Passo 2: Aggiungere un Resolve Guard alla rotta.

In app-routing.module.ts, cambiare la seguente linea di codice { path: 'news', component: NewsComponent } in:

{ path: 'news', component: NewsComponent, resolve: { news: NewsResolver }}

Tutto quello che abbiamo fatto qui è stato aggiungere il resolve guard appena definito alla nostra rotta news. Questo dice ad Angular che dobbiamo aspettare che il metodo resolve() di NewsResolver restituisca i dati prima di visualizzare il NewsComponent.

È importante sottolineare che news nella linea news: NewsResolver di codice è quello che ho scelto per chiamare qualsiasi dato restituito dal resolver. Potete chiamarlo come volete.

Come nota un po’ tangenziale – se non avete familiarità con le guardie di percorso Angular in generale, e volete saperne di più, la documentazione è qui. Entrare nei dettagli delle guardie è fuori dallo scopo di questo post, ma dovete sapere che ci sono altre guardie oltre a resolve disponibili, che è il motivo per cui ho tirato fuori il termine.

Codice con la Resolve Guard aggiunta

Step 3: ottenere i dati risolti dalla rotta attivata del componente.

Ora che abbiamo una classe resolver e l’abbiamo aggiunta alla nostra rotta, i dati vengono pre-fetched. Il passo finale è quello di accedere ai dati pre-fetched nel nostro NewsComponent situato in app/news.component.ts. Navigate in quel file e aggiungete il seguente modulo ES6:

import { ActivatedRoute } from '@angular/router';

poi fornite ActivatedRoute nel costruttore del componente News aggiungendo il seguente codice in cima alla definizione della classe NewsComponent:

constructor(private route: ActivatedRoute) {}

Come sapete, o potreste aver indovinato, ActivatedRoute ci permette di accedere alle informazioni sulla rotta attualmente attiva, come l’url della rotta, i parametri della query, ecc. Quello che ci interessa qui sono i dati delle notizie che vengono caricati nel ActivatedRoute dal resolve guard. Per ottenere i dati delle notizie risolte dalla rotta, aggiungete una proprietà per contenere i dati delle notizie:

public news: any;

e poi ottenete i dati dalla rotta attivata quando la NewsComponent viene inizializzata:

 ngOnInit(): void { this.news = this.route.snapshot.data; }

Questo è praticamente tutto. Cambiate il template del componente news per visualizzare le notizie dalla route resolve rimuovendo i contenuti attuali:

<div>This is just a placeholder for now. News will go here. </div>

e sostituendoli con:

Ora dovreste essere accolti dalle ultime notizie, “Il cielo è blu”, quando cliccate sulla scheda News.

Codice finito

Note & Consigli

– Le risoluzioni possono causare chiamate API ridondanti: Una risoluzione ottiene dati ogni volta che un componente viene caricato. Questo spesso si traduce in chiamate API non necessarie che influiscono negativamente sulle prestazioni. Se la vostra risoluzione ottiene dati che non cambiano frequentemente, considerate di scrivere i dati restituiti dalla risoluzione in una proprietà della classe resolver e semplicemente restituite tale proprietà se è già stata impostata. Per esempio, nel nostro esempio, aggiungeremmo una proprietà news inizialmente non definita in questo modo: public news: any = undefined; nel nostro risolutore di notizie. Poi, nel metodo resolve(), controlliamo se la proprietà news è già impostata e restituiamo il suo valore senza fare una chiamata API se lo è, cioè:

 resolve(): Observable<any> { if (this.news) { return this.getSavedNews(); } else { return this.getNewsFromApi() } }

Esempio completo di codice qui sotto. Se la sintassi degli osservabili vi sembra un po’ insolita, è perché sto usando RxJS 6. C’è un buon tutorial sui cambiamenti recentemente introdotti in RxJS qui se avete bisogno di un ripasso.

Ritornare i dati salvati, se già recuperati dall’API

Naturalmente, si potrebbe andare oltre e impostare un periodo di tempo durante il quale i dati sono validi non solo salvando i dati, ma aggiungendo un’altra proprietà timestamp e facendo una chiamata API se i dati sono più vecchi di x.

– Proprio come in AngularJS, è possibile utilizzare più resolve sulla stessa rotta. Le chiamate resolve sono fatte in parallelo e il componente si caricherà solo dopo che tutte le chiamate avranno restituito i dati. Per usare risoluzioni multiple, basta aggiungerle alla rotta:

Allora i dati di risoluzione aggiuntivi possono essere accessibili dall’istantanea della rotta proprio come una singola risoluzione:

 ngOnInit(): void { this.news = this.route.snapshot.data; this.alternativeNews = this.route.snapshot.data; }

Codice con risoluzioni multiple

– Il resolver ha accesso ai parametri della rotta. Diciamo che avete un componente che mostra una lista di titoli di notizie. Quando si clicca su una storia, si apre un altro componente che mostra l’articolo completo. Prima di caricare quel componente, abbiamo bisogno di pre-caricare il contenuto della notizia il cui titolo è stato cliccato – questo può essere fatto nel metodo resolve. La classe resolver ha accesso al ActivatedRoute, quindi possiamo ottenere l’id della storia che è stata cliccata:

 resolve(route: ActivatedRouteSnapshot) { let id: any = route.params); return this.getNewsStory(id); }

Questo è abbastanza autoesplicativo. Per un esempio, guardate il nuovo file src/news-story-resolver.service.ts nel link qui sotto. I collegamenti al nuovo componente sono stati aggiunti nella scheda News (news.component.ts).

Codice con risoluzione parametrizzata

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.