Angular 2
Routing (3.0.0+)
Suche…
Bemerkungen
Es gibt ein paar weitere Tricks, die wir mit dem Router machen können (z. B. Zugriffsbeschränkungen), aber diese können in einem separaten Tutorial behandelt werden.
Wenn Sie eine neue Route benötigen, ändern app.routes.ts
einfach app.routes.ts
und führen Sie die folgenden Schritte aus:
- Importieren Sie die Komponente
- Fügen Sie das
routes
Array hinzu. Stellen Sie sicher, dass Sie einen neuenpath
und eine neuecomponent
.
Bootstrapping
Jetzt, da die Routen definiert sind, müssen wir unsere Anwendung über die Routen informieren. Bootstrap des Anbieters, den wir im vorherigen Beispiel exportiert haben.
Finden Sie Ihre Bootstrap-Konfiguration (sollte sich in main.ts
, Ihre Laufleistung kann jedoch variieren ).
//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));
Router-Steckdose konfigurieren
Nun, da der Router konfiguriert ist und unsere App mit den Routen umgehen kann, müssen die tatsächlichen Komponenten angezeigt werden, die wir konfiguriert haben.
Konfigurieren Sie dazu Ihre HTML-Vorlage / Datei für Ihre Komponente der obersten Ebene (App- Komponente) wie folgt:
//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>
Das Element <router-outlet></router-outlet>
wechselt den Inhalt anhand der Route. Ein weiterer guter Aspekt dieses Elements ist, dass es nicht das einzige Element in Ihrem HTML-Code sein muss.
Beispiel: Angenommen, Sie wollten auf jeder Seite eine Symbolleiste, die zwischen den Routen konstant bleibt, ähnlich wie der Stapelüberlauf aussieht. Sie können den <router-outlet>
unter Elementen verschachteln, sodass nur bestimmte Teile der Seite geändert werden.
Routen ändern (mithilfe von Vorlagen und Anweisungen)
Nun, da die Routen eingerichtet sind, brauchen wir einen Weg, um die Routen tatsächlich zu ändern.
In diesem Beispiel wird gezeigt, wie Routen mithilfe der Vorlage geändert werden. Es ist jedoch möglich, Routen in TypeScript zu ändern.
Hier ist ein Beispiel (ohne Bindung):
<a routerLink="/home">Home</a>
Wenn der Benutzer auf diesen Link klickt, wird er nach /home
. Der Router weiß, wie mit /home
umzugehen ist, und zeigt die Home
Komponente an.
Hier ein Beispiel mit Datenbindung:
<a *ngFor="let link of links" [routerLink]="link">{{link}}</a>
Für das app.ts
eines Arrays, das als links
, müssen Sie dies zu app.ts
hinzufügen:
public links[] = [
'home',
'login'
]
Dadurch wird das Array durchlaufen und ein <a>
-Element mit der routerLink
Direktive = dem Wert des aktuellen Elements im Array routerLink
Dies erzeugt routerLink
:
<a routerLink="home">home</a>
<a routerLink="login">login</a>
Dies ist besonders hilfreich, wenn Sie viele Links haben oder die Links ständig geändert werden müssen. Wir lassen Angular die anstrengende Arbeit beim Hinzufügen von Links erledigen, indem wir einfach die benötigten Informationen eingeben.
Im Moment ist links[]
statisch, es ist jedoch möglich, Daten aus einer anderen Quelle einzugeben.
Routen einstellen
HINWEIS: Dieses Beispiel basiert auf der Version 3.0.0.-beta.2 des @ angle / router. Zum Zeitpunkt des Schreibens ist dies die neueste Version des Routers.
Um den Router zu verwenden, definieren Sie die Routen in einer neuen TypeScript-Datei wie dieser
//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);
In der ersten Zeile importieren wir " provideRouter
damit unsere Anwendung während der Bootstrap-Phase über die Routen provideRouter
werden kann.
Home
und Profile
sind nur zwei Komponenten. Sie müssen jede Component
Sie benötigen, als Route importieren.
Exportieren Sie dann das Array von Routen.
path
: Der Pfad zur Komponente. SIE MÜSSEN NICHT '/ ........' VERWENDEN . Angular führt dies automatisch aus
component
: Die Komponente, die geladen werden soll, wenn auf die Route zugegriffen wird
redirectTo
: Optional . Wenn Sie einen Benutzer beim Zugriff auf eine bestimmte Route automatisch umleiten müssen, geben Sie dies an.
Zum Schluss exportieren wir den konfigurierten Router. provideRouter
eines Providers von providerRouter, damit wir unsere Route verbessern können.
Zugriff auf oder von einer Route steuern
Der Standard-Angular-Router ermöglicht die uneingeschränkte Navigation von und zu jeder Route. Dies ist nicht immer das gewünschte Verhalten.
In einem Szenario, in dem ein Benutzer unter Umständen dazu berechtigt ist, zu einer Route zu navigieren oder von dieser abzureisen, kann ein Route Guard verwendet werden, um dieses Verhalten einzuschränken.
Wenn Ihr Szenario eine der folgenden Bedingungen erfüllt, ziehen Sie die Verwendung eines Route Guard in Betracht.
- Der Benutzer muss authentifiziert sein, um zur Zielkomponente zu navigieren.
- Der Benutzer muss berechtigt sein, zur Zielkomponente zu navigieren.
- Komponente erfordert vor der Initialisierung eine asynchrone Anforderung.
- Die Komponente erfordert eine Benutzereingabe, bevor von navigiert wird.
Funktionsweise von Route Guards
Route Guards funktionieren, indem sie einen booleschen Wert zurückgeben, um das Verhalten der Routernavigation zu steuern. Wenn true zurückgegeben wird, fährt der Router mit der Navigation zur Zielkomponente fort. Wenn false zurückgegeben wird, verweigert der Router die Navigation zur Zielkomponente.
Route Guard-Schnittstellen
Der Router unterstützt mehrere Guard-Schnittstellen:
- CanActivate : tritt zwischen Routennavigation auf.
- CanActivateChild : tritt zwischen der Routennavigation zu einer untergeordneten Route auf.
- CanDeactivate : tritt auf, wenn Sie von der aktuellen Route weg navigieren.
- CanLoad : tritt zwischen der Routennavigation zu einem asynchron geladenen Funktionsmodul auf.
- Auflösen : Dient zum Abrufen von Daten vor der Aktivierung der Route.
Diese Schnittstellen können in Ihrem Guard implementiert werden, um Zugriff auf bestimmte Prozesse der Navigation zu gewähren oder zu entfernen.
Synchronous vs. Asynchronous Route Guards
Routenschutz ermöglicht synchrone und asynchrone Vorgänge zur bedingten Steuerung der Navigation.
Synchroner Routenschutz
Ein synchroner Routenwächter gibt einen Booleschen Wert zurück, z. B. durch Berechnen eines unmittelbaren Ergebnisses, um die Navigation bedingt zu steuern.
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
Asynchroner Routenschutz
Für komplexeres Verhalten kann ein Route Guard die Navigation asynchron blockieren. Ein asynchroner Route Guard kann ein Observable oder Promise zurückgeben.
Dies ist nützlich, wenn beispielsweise auf die Beantwortung einer Frage auf Benutzereingaben gewartet wird, auf das erfolgreiche Speichern der Änderungen auf dem Server gewartet wird oder auf den Empfang von Daten, die von einem Remote-Server abgerufen werden.
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;
});
}
}
Wächter zur Routenkonfiguration hinzufügen
Datei app.routes
Geschützte Routen haben canActivate
binded 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] }
}
Exportieren Sie das APP_ROUTER_PROVIDERS , das in App-Bootstrap verwendet werden soll
export const APP_ROUTER_PROVIDERS = [
AuthGuard,
provideRouter(routes)
];
Verwenden Sie Guard im App-Bootstrap
Datei main.ts (oder boot.ts )
Betrachten Sie die obigen Beispiele:
- Erstellen Sie die Wache (wo die Wache erstellt wird) und
- Guard zur Routenkonfiguration hinzufügen (wenn der Guard für die Route konfiguriert ist, wird APP_ROUTER_PROVIDERS exportiert)
Wir können den Bootstrap wie folgt an Guard koppeln
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));
Resolver und Guards verwenden
Wir verwenden einen Toplevel-Guard in unserer Routenkonfiguration, um den aktuellen Benutzer beim Laden der ersten Seite currentUser
, und einen Resolver, um den Wert des aktuellen Benutzers, des authentifizierten Benutzers aus dem Backend, zu speichern.
Eine vereinfachte Version unserer Implementierung sieht folgendermaßen aus:
Hier ist unsere Top-Level-Route:
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
Hier ist unser 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);
}
}
Hier ist unser 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);
}
}
Hier ist unser 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;
}
}