Az Angular-ban a függőségek kezelése, különösen a szolgáltatók különböző hatókörökkel történő használata, lehetővé teszi a finomhangolt alkalmazásstruktúrák kialakítását. Az egyik legfontosabb koncepció a szolgáltatói hatókörök (provider scopes) különbözősége. Ezen hatókörök, mint az any és a platform, kulcsszerepet játszanak abban, hogyan kezeljük a szolgáltatásokat különböző modulokban vagy alkalmazásokban.

Az any szolgáltatói hatókör, amint azt az előző példákban bemutattuk, egy egyedi példányt biztosít minden egyes Angular modul számára. Ez azt jelenti, hogy minden modul saját függőség-eltartó példányt kap, függetlenül attól, hogy ugyanaz a szolgáltatás vagy konfiguráció van-e használatban több modulban. Például a SharesComponent és a BankAccountsComponent ugyanazt a BackendService-t használják, de mivel a szolgáltatás a megfelelő modulhoz van kötve, az egyes komponensek a saját konfigurációjukat használják.

A BankAccountsModule nem biztosít backend konfigurációt, így annak szolgáltatásai az alapértelmezett beállítást követik, amely az AppModule-ban van regisztrálva. Az egyes moduloknak különböző példányai lehetnek a BackendService-nek, attól függően, hogy az egyes modulok hogyan konfigurálják a szolgáltatásokat.

Ez az elkülönített példányosítás hasznos lehet olyan esetekben, amikor az alkalmazás különböző részei eltérő adatforrást vagy konfigurációkat használnak, ugyanakkor megőrizzük a kód modularitását és tisztaságát. Az ilyen típusú konfigurálás az any szolgáltatói hatókör segítségével lehetővé teszi, hogy egy szolgáltatás minden modulhoz egyedileg legyen biztosítva anélkül, hogy globálisan hatna az egész alkalmazásra.

A platform szolgáltatói hatókör egy egyszerűbb koncepciót képvisel, és a platform szintű szingletként működik. Az egyes Angular alkalmazások, amelyek ugyanazon az oldalon vannak betöltve, osztoznak a platform szolgáltatói hatókörben regisztrált szolgáltatásokon. Ez a megoldás különösen hasznos lehet, ha mikrofront-endek vagy Angular elemeket használunk. A mikrofront-endek esetén minden alkalmazás különálló Angular alkalmazásként működik, mégis megoszthatják ugyanazokat a függőségeket.

Például, ha van egy Documents alkalmazás és egy Music alkalmazás, mindkettő használhatja ugyanazt a storageToken-t a platform szolgáltatói hatókörön keresztül. Az Angular-ban a platform hatókör a következőképpen van beállítva:

typescript
import { InjectionToken } from '@angular/core';
export const storageToken = new InjectionToken('Web Storage API', { factory: (): Storage => localStorage, providedIn: 'platform', });

Ezáltal a DocumentsService és a MusicService különálló Angular alkalmazásokban ugyanazt a localStorage-ot használják, anélkül, hogy szükség lenne bármilyen különleges beállításra a szolgáltatásokban.

A platform szolgáltatói hatókör egyik legnagyobb előnye, hogy lehetőséget biztosít arra, hogy ugyanazokat a függőségeket osztozó alkalmazások vagy webkomponensek között megoszthassuk, miközben minimalizáljuk a redundanciát és egyszerűsítjük az alkalmazás struktúráját. Ez lehetővé teszi az Angular alkalmazások és Angular Elemetek közötti hatékony kommunikációt és adatmegosztást.

Az any és a platform szolgáltatói hatókörök használatának megértése nemcsak az alkalmazás struktúrájának optimalizálásában segít, hanem a különböző Angular alkalmazások közötti együttműködést és az alkalmazások közötti adatmegosztást is hatékonyabbá teszi. Az alkalmazásfejlesztésben fontos figyelni a különböző modulok közötti hatókörökre, hogy biztosítsuk a tiszta, jól karbantartható és rugalmas kódot, amely képes alkalmazkodni a bővülő igényekhez és összetettebb alkalmazásstruktúrákhoz.

A további fejlődés érdekében érdemes megfontolni a különböző szintű konfigurációk kezelését is, különösen, ha többféle adatforrást és szolgáltatást kell integrálni. Az Angular-ban való dolgozás során alapvető, hogy az alkalmazás különböző részeinek izolált módon biztosítsunk függőségeket, miközben megőrizzük a központi, platform szintű erőforrásokhoz való hozzáférést.

Hogyan szervezzük az adatokat és építsük fel az Angular alkalmazást?

Az alkalmazások tervezésénél fontos elválasztani az adatlekérést és tárolást az egyes komponensek tényleges használatától. Mielőtt hozzákezdenénk az új Angular komponensek használatához, célszerű először felállítani egy adatmodellt, amely segít strukturálni az adatokat és biztosítja a hatékony kommunikációt a backenddel. Az Angular környezetében a legegyszerűbb módja ennek TypeScript interfészek alkalmazása, miközben Angular szolgáltatásokat használunk az adatok lekérésére.

Az általunk használt adatmodellek a következők:

  • Iskola

  • Kurzus

  • Videó

Az előző fejezetben bemutatott videólista egy adott kurzushoz tartozik, amelyet egy iskola hozott létre. A kurzus alapinformációi a következők: egy cím, egy opcionális leírás, és egy lista a videókról, amelyeket a felhasználó megnézhet. Az alábbiakban látható egy egyszerű Course (Kurzus) interfész:

typescript
export interface ICourse { id: string; title: string; description?: string; videos: IVideo[]; }

A videók alapvető információi, mint például a YouTube-on való elérhetőség, a feltöltés dátuma, a készítő és egy opcionális leírás, az alábbiak szerint néznek ki:

typescript
export interface IVideo {
externalId: string; // YouTube ID title: string; date: Date; author?: string; description?: string; }

Mivel fontos, hogy megtaláljuk az iskolákat egy térképen, az iskola modellhez hozzárendeljük az iskolák nevét és földrajzi koordinátáit (szélesség és hosszúság):

typescript
export interface ISchool { id: string; name: string; longitude: number; latitude: number; courses: ICourse[]; }

A modell kialakítása után következik a komponensek elrendezésének megtervezése. Az alkalmazást három fő modulra bontjuk, amelyek külön-külön jelennek meg a felhasználói felületen: Kurzusok, Téma és Iskolák. A Kurzus komponens használja az elrendezést, amelyet az 5. fejezetben ismertettünk, és tartalmaz egy Videó komponenst, amely a YouTube-videókat jeleníti meg az Angular YouTube Player modul segítségével.

A Téma komponens a CSS egyedi tulajdonságait használja a megjelenés szabályozására, míg az Iskolák komponens lehetővé teszi a felhasználó számára, hogy megtalálja az iskolát a Google Maps segítségével, és kiválasszon egy kurzust a választott iskola kínálatából. Az alábbiakban bemutatjuk, hogyan készítjük el az alkalmazás navigációját:

typescript
const routes: Routes = [
{ path: '', redirectTo: 'course/1', pathMatch: 'full' },
{
path: 'course/:id', component: CourseComponent },
{ path: 'schools', component: SchoolsComponent },
{
path: 'theme', component: ThemeComponent }, ];

A Kurzus komponens paramétereket igényel, amelyek meghatározzák, melyik kurzust jelenítsük meg. A egyszerűség kedvéért feltételezzük, hogy a felhasználó már be van jelentkezve és a 1-es számú kurzust választotta ki.

Miután az alkalmazást három modulra bontottuk, ideje meghatározni, hogyan illesszük be a szükséges függőségeket a különböző modulokhoz. A modulokat az alábbi módon importáljuk:

typescript
@NgModule({
bootstrap: [AppComponent], declarations: [AppComponent, NavigationComponent], imports: [ CommonModule, BrowserAnimationsModule, RouterModule.forRoot(routes, { initialNavigation: 'enabledNonBlocking' }), LayoutModule, CourseModule, SchoolsModule, ThemeModule, MaterialModule, ], }) export class AppModule {}

A Kurzus modul a Videó modult is tartalmazza:

typescript
@NgModule({
declarations: [CourseComponent], imports: [CommonModule, ThemeModule, VideoModule, MaterialModule], exports: [VideoModule], }) export class CourseModule {}

Az egyes modulok tartalmazzák az adott funkcióhoz szükséges függőségeket, például a VideoModule a YouTubePlayerModult és a ClipboardModult. A Schools modul tartalmazza a GoogleMapsModult:

typescript
@NgModule({
declarations: [SchoolsComponent], imports: [CommonModule, MaterialModule, GoogleMapsModule], }) export class SchoolsModule {}

Ez a fajta moduláris felépítés segít abban, hogy átláthatóbbá váljon az alkalmazás struktúrája, és biztosítja, hogy csak a szükséges függőségek kerüljenek importálásra.

Amikor az alkalmazás felépítésével és a modulok importálásával végeztünk, elérkezett az ideje annak, hogy az adatokat Angular szolgáltatásokon keresztül érjük el. Ehhez a CourseService és a SchoolsService szolgáltatásokat fogjuk használni. Az adatlekérést aszinkron módon végezzük, és az alábbiakban bemutatjuk a CourseService egyszerű példáját:

typescript
@Injectable({ providedIn: 'root' }) export class CourseService { constructor() {}
getCourse(courseId: string): Observable<ICourse> {
return of(mockCourse); // mock adat visszaadása } }

Hasonlóan, a SchoolsService a következőképpen működik:

typescript
@Injectable({ providedIn: 'root' }) export class SchoolsService { constructor() {} getSchools(): Observable<ISchool[]> { return of(mockSchools); // mock iskolák visszaadása } }

Ez az aszinkron adatlekérés segíti a komponensek közötti adatáramlást, miközben a backenddel való kapcsolattartás is lehetővé válik.

A navigáció beállítása után a felhasználók könnyedén válthatnak a kurzusok és iskolák között, és testre szabhatják a megjelenést a téma beállításainak megfelelően. A navigáció az oldalsó menüből érhető el, és a felhasználó egyszerűen választhat a különböző lehetőségek közül, mint a "Következő kurzus megtekintése", "Iskola keresése", vagy a "Téma szerkesztése".

Fontos, hogy az alkalmazás építése során mindig figyeljünk a modulok közötti tiszta határokra és az aszinkron adatkezelésre. Ez biztosítja, hogy az alkalmazás bővítése és karbantartása hosszú távon is fenntartható és átlátható maradjon.