Angular 2
Routage (3.0.0+)
Recherche…
Remarques
Il y a quelques astuces que nous pouvons faire avec le routeur (telles que la restriction de l'accès), mais celles-ci peuvent être abordées dans un didacticiel séparé.
Si vous avez besoin d'un nouvel itinéraire, modifiez simplement app.routes.ts
et suivez les étapes suivantes:
- Importer le composant
- Ajouter au tableau des
routes
. Assurez-vous d'inclure un nouveaupath
etcomponent
.
Bootstrap
Maintenant que les routes sont définies, nous devons informer notre application des itinéraires. Pour ce faire, démarrez le fournisseur que nous avons exporté dans l'exemple précédent.
Trouvez votre configuration bootstrap (devrait être dans main.ts
, mais votre kilométrage peut varier ).
//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));
Configuration du routeur
Maintenant que le routeur est configuré et que notre application sait comment gérer les itinéraires, nous devons afficher les composants réels que nous avons configurés.
Pour ce faire, configurez votre modèle / fichier HTML pour votre composant de niveau supérieur (app) comme suit:
//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>
L'élément <router-outlet></router-outlet>
changera le contenu de l'itinéraire. Un autre aspect intéressant de cet élément est qu'il ne doit pas nécessairement être le seul élément de votre code HTML.
Par exemple: Supposons que vous souhaitiez une barre d’outils sur chaque page qui reste constante entre les itinéraires, de la même manière que Stack Overflow. Vous pouvez imbriquer les <router-outlet>
sous les éléments afin que seules certaines parties de la page changent.
Changer d'itinéraires (à l'aide de modèles et de directives)
Maintenant que les routes sont configurées, nous avons besoin d'un moyen de changer les routes.
Cet exemple montre comment modifier les itinéraires à l'aide du modèle, mais il est possible de modifier les itinéraires dans TypeScript.
Voici un exemple (sans engagement):
<a routerLink="/home">Home</a>
Si l'utilisateur clique sur ce lien, il sera acheminé vers /home
. Le routeur sait comment gérer /home
, il affichera donc le composant Home
.
Voici un exemple de liaison de données:
<a *ngFor="let link of links" [routerLink]="link">{{link}}</a>
Ce qui nécessiterait un tableau appelé links
pour exister, alors ajoutez ceci à app.ts
:
public links[] = [
'home',
'login'
]
Cela routerLink
le tableau et ajoutera un élément <a>
avec la directive routerLink
= la valeur de l'élément actuel dans le tableau, en créant ceci:
<a routerLink="home">home</a>
<a routerLink="login">login</a>
Cela est particulièrement utile si vous avez beaucoup de liens ou si les liens doivent être constamment modifiés. Nous avons laissé Angular gérer le travail acharné d’ajout de liens en lui fournissant simplement les informations dont il a besoin.
Actuellement, les links[]
sont statiques, mais il est possible de les alimenter depuis une autre source.
Définir les itinéraires
REMARQUE: Cet exemple est basé sur la version 3.0.0.-beta.2 du @ angular / router. Au moment de la rédaction de ce document, il s’agit de la dernière version du routeur.
Pour utiliser le routeur, définissez des itinéraires dans un nouveau fichier TypeScript comme celui-ci.
//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);
Dans la première ligne, nous importons provideRouter
afin que nous puissions informer notre application des routes au cours de la phase de démarrage.
Home
et Profile
sont que deux composants à titre d'exemple. Vous devrez importer chaque Component
vous avez besoin en tant que route.
Ensuite, exportez le tableau des routes.
path
: chemin d'accès au composant. VOUS N'AVEZ PAS BESOIN D'UTILISER '/ ........ Angular le fera automatiquement
component
: composant à charger lors de l'accès à l'itinéraire
redirectTo
: Facultatif . Si vous devez rediriger automatiquement un utilisateur lorsqu'il accède à un itinéraire particulier, indiquez-le.
Enfin, nous exportons le routeur configuré. provideRouter
retournera un fournisseur que nous pouvons booster afin que notre application sache comment gérer chaque route.
Contrôle de l'accès à ou à partir d'une route
Le routeur angulaire par défaut permet la navigation vers et depuis n'importe quel itinéraire sans condition. Ce n'est pas toujours le comportement souhaité.
Dans un scénario où un utilisateur peut être autorisé, à titre conditionnel, à naviguer vers ou à partir d'une route, une fonction Route Guard peut être utilisée pour limiter ce comportement.
Si votre scénario correspond à l’un des suivants, envisagez d’utiliser une garde de route,
- L'utilisateur doit être authentifié pour accéder au composant cible.
- L'utilisateur doit être autorisé à accéder au composant cible.
- Le composant nécessite une requête asynchrone avant l'initialisation.
- Le composant nécessite une entrée utilisateur avant de quitter.
Comment fonctionnent les gardes de route
Les gardes de route fonctionnent en renvoyant une valeur booléenne pour contrôler le comportement de la navigation du routeur. Si true est renvoyé, le routeur continuera à naviguer vers le composant cible. Si false est renvoyé, le routeur refuse la navigation vers le composant cible.
Interfaces de garde de route
Le routeur prend en charge plusieurs interfaces de garde:
- CanActivate : se produit entre la navigation de route.
- CanActivateChild : se produit entre la navigation de l'itinéraire vers un itinéraire enfant.
- CanDeactivate : se produit lorsque vous vous éloignez de l'itinéraire actuel.
- CanLoad : se produit entre la navigation de l'itinéraire vers un module de fonctions chargé de manière asynchrone.
- Résoudre : permet d'effectuer une récupération de données avant l'activation de la route.
Ces interfaces peuvent être implémentées dans votre garde pour accorder ou supprimer l'accès à certains processus de la navigation.
Gardes de route synchrone vs asynchrone
Les gardes de route permettent aux opérations synchrones et asynchrones de contrôler conditionnellement la navigation.
Garde de route synchrone
Une protection de route synchrone renvoie un booléen, par exemple en calculant un résultat immédiat, afin de contrôler la navigation de manière conditionnelle.
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
Garde de route asynchrone
Pour un comportement plus complexe, une protection de route peut bloquer la navigation de manière asynchrone. Un protecteur d'itinéraire asynchrone peut renvoyer une observation ou une promesse.
Ceci est utile dans les situations telles que l'attente d'une entrée utilisateur pour répondre à une question, l'attente d'une sauvegarde réussie des modifications sur le serveur ou l'attente de recevoir des données extraites d'un serveur distant.
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;
});
}
}
Ajouter un garde à la configuration de l'itinéraire
Fichier app.routes
Les itinéraires protégés canActivate
être canActivate
sur 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] }
}
Exportez les APP_ROUTER_PROVIDERS à utiliser dans le bootstrap de l'application
export const APP_ROUTER_PROVIDERS = [
AuthGuard,
provideRouter(routes)
];
Utilisez Guard dans l'application bootstrap
Fichier main.ts (ou boot.ts )
Considérons les exemples ci-dessus:
- Créer la garde (où la garde est créée) et
- Ajouter la garde à la configuration de la route , (où la garde est configurée pour la route, alors APP_ROUTER_PROVIDERS est exporté),
nous pouvons coupler le bootstrap à Guard comme suit
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));
Utiliser des résolveurs et des gardes
Nous utilisons une protection de niveau supérieur dans notre route config pour intercepter l'utilisateur actuel sur la première page et un résolveur pour stocker la valeur de currentUser
, qui est notre utilisateur authentifié du serveur.
Une version simplifiée de notre implémentation se présente comme suit:
Voici notre itinéraire de haut niveau:
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
Voici notre 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);
}
}
Voici notre 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);
}
}
Voici notre 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;
}
}