Angular 2
Routing (3.0.0+)
Sök…
Anmärkningar
Det finns några fler trick vi kan göra med routern (som att begränsa åtkomst), men de kan behandlas i en separat handledning.
Om du behöver en ny rutt, ändra helt enkelt app.routes.ts
och följ följande steg:
- Importera komponenten
- Lägg till
routes
array. Se till att inkludera en nypath
ochcomponent
.
Bootstrapping
Nu när rutterna är definierade måste vi informera vår ansökan om rutterna. För att göra detta, starta om leverantören som vi exporterade i föregående exempel.
Hitta din bootstrap-konfiguration (ska vara i main.ts
, men din körsträcka kan variera ).
//main.ts
import {bootstrap} from '@angular/platform-browser-dynamic';
//Import the App component (root component)
import { App } from './app/app';
//Also import the app routes
import { APP_ROUTES_PROVIDER } from './app/app.routes';
bootstrap(App, [
APP_ROUTES_PROVIDER,
])
.catch(err => console.error(err));
Konfigurera router-uttag
Nu när routern är konfigurerad och vår app vet hur hanterar rutterna måste vi visa de faktiska komponenterna som vi konfigurerade.
För att göra det konfigurerar du din HTML-mall / fil för din toppnivå (app) -komponent så:
//app.ts
import {Component} from '@angular/core';
import {Router, ROUTER_DIRECTIVES} from '@angular/router';
@Component({
selector: 'app',
templateUrl: 'app.html',
styleUrls: ['app.css'],
directives: [
ROUTER_DIRECTIVES,
]
})
export class App {
constructor() {
}
}
<!-- app.html -->
<!-- All of your 'views' will go here -->
<router-outlet></router-outlet>
Elementet <router-outlet></router-outlet>
byter innehåll som ges rutten. En annan bra aspekt om detta element är att det inte behöver vara det enda elementet i din HTML.
Till exempel: Låt oss säga att du ville ha ett verktygsfält på varje sida som förblir konstant mellan rutter, liknande hur Stack Overflow ser ut. Du kan häcka <router-outlet>
under element så att endast vissa delar av sidan ändras.
Ändra rutter (med mallar och direktiv)
Nu när rutterna är inställda behöver vi något sätt att faktiskt ändra rutter.
Detta exempel visar hur du ändrar rutter med mallen, men det är möjligt att ändra rutter i TypeScript.
Här är ett exempel (utan bindning):
<a routerLink="/home">Home</a>
Om användaren klickar på den länken kommer den att ruta till /home
. Routern vet hur man hanterar /home
, så det kommer att visa Home
Component.
Här är ett exempel med databindning:
<a *ngFor="let link of links" [routerLink]="link">{{link}}</a>
Vilket kräver att en grupp som heter links
finns, så lägg till detta i app.ts
:
public links[] = [
'home',
'login'
]
Detta kommer att slinga genom arrayen och lägga till ett <a>
element med routerLink
direktivet = värdet på det aktuella elementet i arrayen, vilket skapar detta:
<a routerLink="home">home</a>
<a routerLink="login">login</a>
Detta är särskilt användbart om du har många länkar, eller kanske behöver länkarna ständigt ändras. Vi låter Angular hantera det upptagna arbetet med att lägga till länkar genom att bara mata den den information den kräver.
Just nu är links[]
statiska, men det är möjligt att mata data från en annan källa.
Ställa in rutter
OBS: Det här exemplet är baserat på 3.0.0.-beta.2-frisläppandet av @ vinkel / routern. I skrivande stund är detta den senaste versionen av routern.
Om du vill använda routern definierar du rutter i en ny TypeScript-fil som sådan
//app.routes.ts
import {provideRouter} from '@angular/router';
import {Home} from './routes/home/home';
import {Profile} from './routes/profile/profile';
export const routes = [
{path: '', redirectTo: 'home'},
{path: 'home', component: Home},
{path: 'login', component: Login},
];
export const APP_ROUTES_PROVIDER = provideRouter(routes);
I den första raden importerar vi provideRouter
så att vi kan låta vår applikation veta vilka rutter är under uppstartfasen.
Home
och Profile
är bara två komponenter som exempel. Du måste importera varje Component
du behöver som en rutt.
Exportera sedan mängden rutter.
path
: Sökvägen till komponenten. DU BEHÖVER INTE ANVÄNDA '/ ........' Angular gör detta automatiskt
component
: Komponenten som ska laddas när rutten nås
redirectTo
: Valfritt . Om du måste omdirigera en användare automatiskt när de kommer åt en viss rutt, ange detta.
Slutligen exporterar vi den konfigurerade routern. provideRouter
returnerar en leverantör som vi kan boostrap så vår ansökan vet hur man hanterar varje rutt.
Kontrollera åtkomst till eller från en rutt
Standardvinkelrutern tillåter navigering till och från alla rutter utan villkor. Detta är inte alltid det önskade beteendet.
I ett scenario där en användare villkorligen får tillåtas att navigera till eller från en rutt, kan en ruttvakt användas för att begränsa detta beteende.
Om ditt scenario passar något av följande bör du överväga att använda en ruttvakt,
- Användaren måste autentiseras för att navigera till målkomponenten.
- Användaren måste ha behörighet att navigera till målkomponenten.
- Komponenten kräver asynkron begäran innan initialisering.
- Komponent kräver användarinmatning innan du navigerar bort från.
Hur vägbeskydd fungerar
Ruttvakter fungerar genom att returnera ett booleskt värde för att kontrollera beteendet med routernavigering. Om true returneras fortsätter routern med navigering till målkomponenten. Om falskt returneras avvisar routern navigering till målkomponenten.
Ruttvaktgränssnitt
Routern stöder flera skyddsgränssnitt:
- CanActivate : sker mellan ruttnavigering.
- CanActivateChild : inträffar mellan ruttnavigering till en barnväg.
- CanDeactivate : inträffar när du navigerar bort från den aktuella rutten.
- CanLoad : sker mellan ruttnavigering till en funktionsmodul som laddas asynkront.
- Lös : används för att utföra datainsamling innan ruttaktivering.
Dessa gränssnitt kan implementeras i din vakt för att bevilja eller ta bort åtkomst till vissa navigeringsprocesser.
Synkrona kontra asynkrona ruttskydd
Ruttvakter tillåter synkrona och asynkrona funktioner för att kontrollera navigeringen.
Synkron vägskydd
En synkron ruttskydd returnerar en boolean, t.ex. genom att beräkna ett omedelbart resultat, för att villkorligt kontrollera navigering.
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
Asynkron vägvakt
För mer komplicerat beteende kan en ruttvakt asynkront blockera navigering. En asynkron ruttvakt kan returnera en observerbar eller löfte.
Detta är användbart i situationer som att vänta på användarinmatning för att svara på en fråga, vänta på att framgångsrikt spara ändringar på servern eller vänta på att få data hämtad från en fjärrserver.
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Rx';
import { MockAuthenticationService } from './authentication/authentication.service';
@Injectable()
export class AsynchronousGuard implements CanActivate {
constructor(private router: Router, private auth: MockAuthenticationService) {}
canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
this.auth.subscribe((authenticated) => {
if (authenticated) {
return true;
}
this.router.navigateByUrl('/login');
return false;
});
}
}
Lägg till skydd i ruttkonfigurationen
File app.routes
Skyddade rutter har canActivate
bundna till Guard
import { provideRouter, Router, RouterConfig, CanActivate } from '@angular/router';
//components
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
export const routes: RouterConfig = [
{ path: 'login', component: LoginComponent },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
}
Exportera APP_ROUTER_PROVIDERS som ska användas i startsteg för app
export const APP_ROUTER_PROVIDERS = [
AuthGuard,
provideRouter(routes)
];
Använd Guard i appens bootstrap
Fil main.ts (eller boot.ts )
Tänk på exemplen ovan:
- Skapa skyddet (där vakten skapas) och
- Lägg till vakt i ruttkonfigurationen (där vakten är konfigurerad för rutt, sedan exporteras APP_ROUTER_PROVIDERS ),
vi kan koppla ihop bootstrap till Guard enligt följande
import { bootstrap } from '@angular/platform-browser-dynamic';
import { provide } from '@angular/core';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { AppComponent } from './app.component';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.then(success => console.log(`Bootstrap success`))
.catch(error => console.log(error));
Använda Resolvers och vakter
Vi använder en toppnivåskydd i vår ruttkonfiguration för att fånga den aktuella användaren på första sidas belastning, och en upplösare för att lagra värdet på den currentUser
, som är vår autentiserade användare från backend.
En förenklad version av vår implementering ser ut enligt följande:
Här är vår toppnivåväg:
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
Här är vår AuthService
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/do';
@Injectable()
export class AuthService {
constructor(http: Http) {
this.http = http;
let headers = new Headers({ 'Content-Type': 'application/json' });
this.options = new RequestOptions({ headers: headers });
}
fetchCurrentUser() {
return this.http.get('/api/users/me')
.map(res => res.json())
.do(val => this.currentUser = val);
}
}
Här är vår AuthGuard
:
import { Injectable } from '@angular/core';
import { CanActivate } from "@angular/router";
import { Observable } from 'rxjs/Rx';
import { AuthService } from '../services/AuthService';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(auth: AuthService) {
this.auth = auth;
}
canActivate(route, state) {
return Observable
.merge(this.auth.fetchCurrentUser(), Observable.of(true))
.filter(x => x == true);
}
}
Här är vår CurrentUserResolver
:
import { Injectable } from '@angular/core';
import { Resolve } from "@angular/router";
import { Observable } from 'rxjs/Rx';
import { AuthService } from '../services/AuthService';
@Injectable()
export class CurrentUserResolver implements Resolve {
constructor(auth: AuthService) {
this.auth = auth;
}
resolve(route, state) {
return this.auth.currentUser;
}
}