Frissítve: 2018.07.13: A kód átfogó átdolgozása az újabb konvenciók használata érdekében. Az Angular és az RxJS frissítése a legújabb elérhető verziókra, a példák áthelyezése a StackBlitzre.
Ez a bejegyzés célja, hogy 10 percben bemutassa, hogyan működik az Angular útvonalfeloldás, valamint a Stackblitz-en található mintakódot is biztosítja. Ha már ismeri az AngularJS-ből származó route resolves-t, javaslom, hogy hagyja ki a bevezetőt, és ugorjon egyenesen a mintaalkalmazás részhez.
Tartalomjegyzék
Előszó
Mintaalkalmazás
- 1. lépés: Resolver osztály létrehozása
- 2. lépés: Resolve Guard hozzáadása az útvonalhoz
- 3. lépés: A feloldott adatok kinyerése a komponens aktivált útvonalából
Jegyzetek & Tippek
- A redundáns API-hívások elkerülése
- Multiple Resolves on ugyanazon az útvonalon
- Az útvonal-paraméterek átadása a feloldónak
Záró megjegyzések
Intro
Az útvonal-feloldások nem mások, mint egy módja annak, hogy a feloldás előtta komponensnek az inicializálás előtt szükséges adatok lekérése. Általában ezek az adatok egy API-ból származnak. Tegyük fel, hogy van egy olyan komponensünk, amelynek egyetlen szerepe az, hogy megjelenítsen egy diagramot a hónap napi eladásáról; Nincs értelme megjeleníteni a nézetet vagy betölteni ezt a komponenst, mielőtt az eladási adatok rendelkezésre állnak. Valójában sok diagramkészítő könyvtár hibát fog dobni, ha megpróbálsz inicializálni egy diagramot, mielőtt megadnád neki az adatokat (és a *ngFor
is). Természetesen ezt a problémát könnyen megkerülhetjük úgy, hogy a html-t egy *ngIf
-el rejtjük el, vagy ideiglenesen egy üres tömböt adunk meg, amíg a szükséges adatok be nem töltődnek. Azonban, bár megoldások nélkül is boldogulhatsz, a megvalósításuk segít olvashatóbbá és karbantarthatóbbá tenni a kódot azáltal, hogy:
- Kiküszöbölöd a zavaró rendetlenséget a komponens sablonjában és kódjában.
- Tisztázza a szándékát azáltal, hogy megmutatja, mely adatokat kell előzetesen betöltetni.
Ezek az előnyök ellenére sok webhely elkerüli a resolve-ok használatát, és inkább a komponens nagy részét jeleníti meg, és egy spinnert jelenít meg azokban a szakaszokban, amelyeknél az adatok betöltése még folyamatban van. Bizonyos esetekben ez a megközelítés UX-szempontból kívánatos, és a feloldást nem szabad használni. Használjuk a saját belátásunkat.
Mintaalkalmazás
Mintaalkalmazás megnyitása
Amint láthatjuk, a kiindulási pontunk egy nagyon egyszerű alkalmazás két útvonallal – “Főoldal” és “Hírek”. Az útvonalak között a megfelelő fülre kattintva navigálhatunk. Hozzáadunk egy feloldást a hírek előzetes lekérdezéséhez egy API-ból, mielőtt a News komponens betöltődik. Ehhez három lépés szükséges:
1. lépés: Hozzunk létre egy resolver osztályt, amely egy Http-hívást hajt végre a szükséges adatok előzetes lekérdezéséhez.
Készítsünk egy új Typescript fájlt a app
mappán belül, és nevezzük el:
news-resolver.service.ts
Ezután másoljuk be az alábbi kódot az új fájlba (alább magyarázzuk):
Bontjuk le, mit csináltunk a fenti kódban:
-
Hozzáadtuk az ES6 import utasításokat a szükséges modulok behozásához.
-
Elkészítettünk egy új TypeScript
NewsResolver
osztályt. -
Hozzáadtuk az
Resolve
interfészt az osztályunkhoz – ez OPCIONÁLIS, de minden olyan osztálynak, amelyet resolverként tervezünk használni, implementálnia kell egy resolve metódust, így ez egy jó konvenció. -
Adtunk egy
resolve()
metódust aNewsResolver
-hez – ez a metódus felelős a nekünk szükséges adatok visszaadásáért. A resolve guard számára adatokat visszaadó metódus elnevezése “resolve” NEM opcionális – a resolver nem működne, ha a metódus neve más lenne. -
Ha észrevetted, hogy a fenti kódban helytelenül egy
POST
kérést használunk egyGET
helyett, akkor teljesen igazad van; Egy valós alkalmazásban ez egyGET
kérés lenne. Az itteni példák kihasználják a-t, amely egy teszt API végpontokat biztosító oldal.
Mielőtt továbblépnénk, be kell építenünk az imént létrehozott resolver osztályt a routing modulunkba. Navigáljunk a app-routing.module.ts
helyre, és adjuk hozzá a NewsResolver
-t a providers
tömbhöz. Vagy ha még csak most kezdünk el dolgozni az Angular 2-vel, egyszerűen cseréljük le a app-routing.module.ts
tartalmát az alábbi kódra – a változásokat jegyzetekkel jelöljük:
Mivel ez megtörtént, most már definiáltuk a resolver osztályt. A következő lépésekben hozzáadjuk az útvonalunkhoz.
Kód a resolver osztály hozzáadása után
2. lépés: Resolve Guard hozzáadása az útvonalhoz.
A app-routing.module.ts
-ben a következő { path: 'news', component: NewsComponent }
kódsort cseréljük ki:
{ path: 'news', component: NewsComponent, resolve: { news: NewsResolver }}
Mindössze annyit tettünk itt, hogy hozzáadtuk az imént definiált resolve guardot a news
útvonalunkhoz. Ez azt mondja az Angularnak, hogy meg kell várnunk, amíg a NewsResolver
resolve()
metódusa visszaadja az adatokat, mielőtt megjelenítjük a NewsComponent
.
Fontos kiemelni, hogy a news: NewsResolver
kódsorban a news
az, amit én választottam, hogy elnevezzük azt az adatot, amit a feloldó visszaad. Azt nevezhetsz el, amit csak akarsz.
Egy kis érintőleges megjegyzésként – ha nem ismered az Angular route guardokat általában, és többet szeretnél tudni, a dokumentáció itt található. A guardok részletezése nem tartozik ennek a posztnak a keretébe, de tudnod kell, hogy a resolve
mellett más guardok is rendelkezésre állnak, ezért hoztam fel a kifejezést.
Kód a Resolve Guard hozzáadásával
3. lépés: A feloldott adatok kinyerése a komponens aktivált route-jából.
Most, hogy van egy resolver osztályunk és hozzáadtuk a route-unkhoz, az adatok előre lekérdezésre kerülnek. Az utolsó lépés az, hogy elérjük az előzetesen lekérdezett adatokat a NewsComponent
-ben található app/news.component.ts
-ünkben. Navigáljunk erre a fájlra, és adjuk hozzá a következő ES6 modult:
import { ActivatedRoute } from '@angular/router';
majd adjuk meg a ActivatedRoute
-t a News komponens konstruktorában a következő kód hozzáadásával a NewsComponent
osztálydefiníció tetején:
constructor(private route: ActivatedRoute) {}
Amint tudjuk, vagy talán már kitaláltuk, a ActivatedRoute
lehetővé teszi számunkra az éppen aktív útvonalra vonatkozó információk elérését, például az útvonal url-jét, lekérdezési paramétereit stb. Ami minket itt érdekel, az a híradat, amely a resolve guardból töltődik be a ActivatedRoute
-be. Ahhoz, hogy a feloldott híradatokat megkapjuk az útvonalból, adjunk hozzá egy tulajdonságot a híradatok tárolására:
public news: any;
majd a NewsComponent
inicializálásakor kapjuk meg az adatokat az aktivált útvonalból:
ngOnInit(): void { this.news = this.route.snapshot.data; }
Ez gyakorlatilag ennyi. Módosítsa a hírkomponens sablonját úgy, hogy az útvonal feloldásából származó híreket jelenítse meg, eltávolítva a jelenlegi tartalmat:
<div>This is just a placeholder for now. News will go here. </div>
és helyettesítve őket:
Ezután a Hírek fülre kattintva a legfrissebb hírekkel, a “Kék az ég” cíművel kell üdvözölnie.
Kész kód
Jegyzetek & Tippek
– A feloldások felesleges API-hívásokat okozhatnak: A feloldás minden alkalommal adatokat kap, amikor egy komponens betöltődik. Ez gyakran felesleges API-hívásokat eredményez, amelyek hátrányosan befolyásolják a teljesítményt. Ha a resolve olyan adatokat kap, amelyek nem változnak gyakran, fontolja meg, hogy a resolve által visszaadott adatokat a resolver osztály egy tulajdonságába írja, és egyszerűen adja vissza ezt a tulajdonságot, ha az már be van állítva. Példánkban például egy kezdetben nem definiált news
tulajdonságot adnánk hozzá a következőképpen: public news: any = undefined;
a hírfeloldónkban. Ezután a resolve()
metódusban ellenőrizzük, hogy a news
tulajdonság már be van-e állítva, és API-hívás nélkül visszaadjuk az értékét, ha igen, azaz:
resolve(): Observable<any> { if (this.news) { return this.getSavedNews(); } else { return this.getNewsFromApi() } }
A teljes kódpélda alább. Ha a megfigyelhető szintaxis kissé szokatlannak tűnik önnek, az azért van, mert a RxJS 6
-t használom. Van egy jó bemutató a RxJS
nemrég bevezetett változásairól itt, ha szükséged van egy kis felfrissítésre.
Return Saved Data, if Already Fetched from API
Naturally, you can go more and set a time period during which the data is valid by not only saving the data, but adding another timestamp property and making an API call if the data is older than x.
– Just like in AngularJS, you can use multiple resolves on the same route. A resolve hívások párhuzamosan történnek, és a komponens csak akkor töltődik be, ha az összes hívás visszaadja az adatokat. Több feloldás használatához egyszerűen hozzá kell adni őket az útvonalhoz:
Ezután a további feloldási adatok elérhetők az útvonal pillanatképéből, akárcsak egyetlen feloldás esetén:
ngOnInit(): void { this.news = this.route.snapshot.data; this.alternativeNews = this.route.snapshot.data; }
Code With Multiple Resolves
– A feloldónak hozzáférése van az útvonalparaméterekhez. Tegyük fel, hogy van egy komponensünk, amely egy listát jelenít meg a hírek címeiből. Amikor egy történetre kattintunk, megnyílik egy másik komponens, amely a teljes cikket mutatja. Mielőtt betöltenénk ezt a komponenst, előzetesen le kell hívnunk annak a hírnek a tartalmát, amelynek a címére kattintottunk – ezt a resolve metódusban tehetjük meg. A resolver osztály hozzáfér a ActivatedRoute
-hez, így megkaphatjuk a történet id-jét, amelyre kattintottak:
resolve(route: ActivatedRouteSnapshot) { let id: any = route.params); return this.getNewsStory(id); }
Ez eléggé magától értetődő. Példaként nézze meg az új src/news-story-resolver.service.ts
fájlt az alábbi linken. Az új komponensre mutató linkeket a Hírek lapon (news.component.ts
) adtuk hozzá.
Code with Parameterized Resolve