Routing - functionalitate oferita de Angular pentru a da impresia mai multor pagini pe care poate naviga un utilizator. In realitate este o singura pagina pe care se plimba mai multe componente.
Pasii pentru inregistrarea rutelor:
1. Rutele trebuie declarate in app.module.ts, exemplu:
const appRoutes = Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent }
]
const appRoutes = Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent }
]
2. In app.module.ts -> @NgModule -> imports, se adauga: RouterModule.forRoot(appRoutes)
3. In fisierul html se adauga: <router-outlet></router-outlet> in locul componentelor care fusesera adaugate folosind selectori (adica in exemplu, in locul lui <app-home> si <app-users>).
La acest moment, accesarea paginii de baza (http://localhost:4200/ si http://localhost:4200/users va duce utilizatorul catre cele 2 componente, dar nu exista navigatie in interior).
4. Adaugarea navigatiei:
- actualizare cu <a href="/"> sau <a href="/users" in html => dezavantaj ca se va face refresh la pagina de fiecare data cand se acceseaza acele link-uri
- inlocuire <a href> cu <a routerLink="/users"> pentru a scapa de refresh. Alternativa este <a [routerLink]="['/users']">
Alternativ (primii 2 pasi):
1. Outsourcing - se creeaza un nou modul "app-routing.module.ts", in care se declara const appRoutes ca la pct.1 (dar in afara definitiei clasei). Clasa va fi adnotata cu:
Tips: <li routerLinkActive="active"> marcheaza ruta activa (via Bootstrap). Se adauga pe <li> care detine link-ul pe care s-a navigat.
Rutare programatica
Se injecteaza Router => se adauga Router in constructor, dupa care se poate folosi intr-o metoda din Typescript cu sintaxa: this.router.navigate(['/users']);
Cai relative: in constructor se injecteaza in plus route: ActivatedRoute
this.router.navigate(['/users'], {relativeTo: this.route});
Cai dinamice:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent }
{ path: 'users/:id', component: UsersComponent }
]
Acum se poate accesa un anume utilizator cu id=3 la http://localhost:4200/users/3:
- id este un camp dintr-o variabila user definita in UsersComponent.
- acestei componente i se injecteaza in constructor route: ActivatedRoute
- id-ul se poate obtine apoi prin this.routes.snapshot.params['id'];
Se pot adauga si alte elemente dinamice: { path: 'users/:id/:name', component: UsersComponent }
!!! Pentru actualizarea obiectului din Typescript cand se apeleaza un link asemanator cu rutare, pentru ca schimbarile sa se propage in template, se adauga: this.route.params.subscribe( (params: Params) -> { this.user.id = params['id']; });
!!! Pentru ca subscriptia sa nu traiasca la nesfarsit in ciuda distrugerii componentei din care face parte, se poate salva ca variabila, iar in ngOnDestroy() se va apela: this.subscription.unsubscribe();
Cai care contin parametri de tip query:
<a [routerLink]="['/users']" [queryParams]="{allowEdit: '1'}" fragment="loading" href="#"> // va duce catre http://localhost:4200/users?allowEdit=1#loading
Echivalent in Typescript: this.router.navigate(['/users'], {queryParams: {allowEdit: '1'}}, fragment: 'loading');
Accesul la parametrii de tip query (non-reactiv la schimbari):
- se injecteaza route: ActivatedRoute in constructor
- se acceseaza prin: this.route.snapshot.queryParams si this.route.snapshot.fragment
Reactiv: se apeleaza subscribe() pe cele 2 variabile, in ngOnInit().
Tips: const id = +this.route.snapshot.params['id']; // va cauza ca id-ul sa fie interpretat ca un numar si nu un string (default)
Nested routes:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent, children: [
{ path: ':id', component: UsersComponent }
]}
]
Pastrarea parametrilor query - this.router.navigate(['/users'], {relativeTo: this.route, queryParamsHandling: 'preserve'}); // optiuni: merge, preserve
Redirectari pentru pagini invalide - se adauga in app.module.ts:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent },
{ path: 'not-found', component: PageNotFoundComponent },
{ path: '**', redirectTo: '/not-found' }
]
'**' este wildcard pt orice altceva. Ordinea este importanta (redirectarea va fi intotdeauna ultima ruta adaugata)
Tips: { path: '', redirectTo: '/somewhere-else', pathMatch: 'full' } pentru ca '' sa nu mai faca match cu absolut orice
Route Guards - functionalitati care se executa inainte sa se incarce o ruta, sau imediat dupa parasirea ei.
export class AuthGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated().then(
(authenticated: boolean) => { if (authenticated) { return true; } else { router.navigate(['/']); } });
}
}
Apoi, pentru a proteja rutele:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', canActivate: [AuthGuard], component: UsersComponent } // va fi accesibila doar daca canActivate() din AuthGuard intoarce true
}
La acest moment, accesarea paginii de baza (http://localhost:4200/ si http://localhost:4200/users va duce utilizatorul catre cele 2 componente, dar nu exista navigatie in interior).
4. Adaugarea navigatiei:
- actualizare cu <a href="/"> sau <a href="/users" in html => dezavantaj ca se va face refresh la pagina de fiecare data cand se acceseaza acele link-uri
- inlocuire <a href> cu <a routerLink="/users"> pentru a scapa de refresh. Alternativa este <a [routerLink]="['/users']">
Alternativ (primii 2 pasi):
1. Outsourcing - se creeaza un nou modul "app-routing.module.ts", in care se declara const appRoutes ca la pct.1 (dar in afara definitiei clasei). Clasa va fi adnotata cu:
@NgModule({ imports: [RouterModule.forRoot(appRoutes)], exports: [RouterModule] })2. In app.module.ts -> @NgModule -> imports, se adauga AppRoutingModule
Tips: <li routerLinkActive="active"> marcheaza ruta activa (via Bootstrap). Se adauga pe <li> care detine link-ul pe care s-a navigat.
Rutare programatica
Se injecteaza Router => se adauga Router in constructor, dupa care se poate folosi intr-o metoda din Typescript cu sintaxa: this.router.navigate(['/users']);
Cai relative: in constructor se injecteaza in plus route: ActivatedRoute
this.router.navigate(['/users'], {relativeTo: this.route});
Cai dinamice:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent }
{ path: 'users/:id', component: UsersComponent }
]
Acum se poate accesa un anume utilizator cu id=3 la http://localhost:4200/users/3:
- id este un camp dintr-o variabila user definita in UsersComponent.
- acestei componente i se injecteaza in constructor route: ActivatedRoute
- id-ul se poate obtine apoi prin this.routes.snapshot.params['id'];
Se pot adauga si alte elemente dinamice: { path: 'users/:id/:name', component: UsersComponent }
!!! Pentru actualizarea obiectului din Typescript cand se apeleaza un link asemanator cu rutare, pentru ca schimbarile sa se propage in template, se adauga: this.route.params.subscribe( (params: Params) -> { this.user.id = params['id']; });
!!! Pentru ca subscriptia sa nu traiasca la nesfarsit in ciuda distrugerii componentei din care face parte, se poate salva ca variabila, iar in ngOnDestroy() se va apela: this.subscription.unsubscribe();
Cai care contin parametri de tip query:
<a [routerLink]="['/users']" [queryParams]="{allowEdit: '1'}" fragment="loading" href="#"> // va duce catre http://localhost:4200/users?allowEdit=1#loading
Echivalent in Typescript: this.router.navigate(['/users'], {queryParams: {allowEdit: '1'}}, fragment: 'loading');
Accesul la parametrii de tip query (non-reactiv la schimbari):
- se injecteaza route: ActivatedRoute in constructor
- se acceseaza prin: this.route.snapshot.queryParams si this.route.snapshot.fragment
Reactiv: se apeleaza subscribe() pe cele 2 variabile, in ngOnInit().
Tips: const id = +this.route.snapshot.params['id']; // va cauza ca id-ul sa fie interpretat ca un numar si nu un string (default)
Nested routes:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent, children: [
{ path: ':id', component: UsersComponent }
]}
]
Pastrarea parametrilor query - this.router.navigate(['/users'], {relativeTo: this.route, queryParamsHandling: 'preserve'}); // optiuni: merge, preserve
Redirectari pentru pagini invalide - se adauga in app.module.ts:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent },
{ path: 'not-found', component: PageNotFoundComponent },
{ path: '**', redirectTo: '/not-found' }
]
'**' este wildcard pt orice altceva. Ordinea este importanta (redirectarea va fi intotdeauna ultima ruta adaugata)
Tips: { path: '', redirectTo: '/somewhere-else', pathMatch: 'full' } pentru ca '' sa nu mai faca match cu absolut orice
Route Guards - functionalitati care se executa inainte sa se incarce o ruta, sau imediat dupa parasirea ei.
export class AuthGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated().then(
(authenticated: boolean) => { if (authenticated) { return true; } else { router.navigate(['/']); } });
}
}
Apoi, pentru a proteja rutele:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', canActivate: [AuthGuard], component: UsersComponent } // va fi accesibila doar daca canActivate() din AuthGuard intoarce true
}
Protejarea rutelor-copii: AuthGuard va implementa si interfata CanActivateChild -> se suprascrie metoda canActivateChild cu aceiasi parametri, in care doar se cheama canActivate(...)
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', canActivateChild: [AuthGuard], component: UsersComponent, children: [
{ path: ':id', component: UsersComponent }
]}
]
Transmiterea de date statice unei rute:
1. in declararea rutei se adauga:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent },
{ path: 'not-found', component: PageNotFoundComponent, data: {message: 'Page not found!'} },
{ path: '**', redirectTo: '/not-found' }
]
2. in TypeScript se injecteaza un ActivatedRoute, iar in ngOnInit() se adauga: this.errorMessage = this.route.snapshot.data['message'];
Eventual se poate inlocui cu urmatoarea linie, daca vrem sa fim la curent cu schimbarile:
this.route.data.subscribe( (data: Data) => { this.errorMessage = data['message']; } );
Transmiterea de date dinamice unei rute:
1. in declararea rutei se adauga:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent, resolve: {detectie: DetectionResolver} }
]
// aici detectie este un keyword ales
2. se declara DetectionResolver ca implementand Resolve<MyDataType>, in care trebuie implementata metoda resolve:
resolve (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<MyDataType> | Promise<MyDataType> | MyDataType {
// aici se poate folosi un serviciu injectat deja in constructor pentru a putea aduce date din exterior
// se va returna obiectul MyDataType continand informatiile dorite (sau un Observable, sau un Promise)
}
3. in TypeScript-ul componentei, in care s-a injectat un route: ActivatedRoute, se poate acum obtine obiectul MyDataType cu informatiile dorite, folosind in cazul de mai sus: this.route.snapshot.data['detectie'];
---
Sursa: cap. 11-12 Udemy
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', canActivateChild: [AuthGuard], component: UsersComponent, children: [
{ path: ':id', component: UsersComponent }
]}
]
Transmiterea de date statice unei rute:
1. in declararea rutei se adauga:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent },
{ path: 'not-found', component: PageNotFoundComponent, data: {message: 'Page not found!'} },
{ path: '**', redirectTo: '/not-found' }
]
2. in TypeScript se injecteaza un ActivatedRoute, iar in ngOnInit() se adauga: this.errorMessage = this.route.snapshot.data['message'];
Eventual se poate inlocui cu urmatoarea linie, daca vrem sa fim la curent cu schimbarile:
this.route.data.subscribe( (data: Data) => { this.errorMessage = data['message']; } );
Transmiterea de date dinamice unei rute:
1. in declararea rutei se adauga:
const appRoutes : Routes [
{ path: '', component: HomeComponent },
{ path: 'users', component: UsersComponent, resolve: {detectie: DetectionResolver} }
]
// aici detectie este un keyword ales
2. se declara DetectionResolver ca implementand Resolve<MyDataType>, in care trebuie implementata metoda resolve:
resolve (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<MyDataType> | Promise<MyDataType> | MyDataType {
// aici se poate folosi un serviciu injectat deja in constructor pentru a putea aduce date din exterior
// se va returna obiectul MyDataType continand informatiile dorite (sau un Observable, sau un Promise)
}
3. in TypeScript-ul componentei, in care s-a injectat un route: ActivatedRoute, se poate acum obtine obiectul MyDataType cu informatiile dorite, folosind in cazul de mai sus: this.route.snapshot.data['detectie'];
---
Sursa: cap. 11-12 Udemy
Niciun comentariu:
Trimiteți un comentariu