Angular 2
Маршрутизация (3.0.0+)
Поиск…
замечания
Есть несколько трюков, которые мы можем сделать с маршрутизатором (например, ограничение доступа), но они могут быть рассмотрены в отдельном учебнике.
Если вам нужен новый маршрут, просто измените app.routes.ts
и выполните следующие действия:
- Импортировать компонент
- Добавьте в массив
routes
. Не забудьте включить новыйpath
иcomponent
.
Бутстрапирование
Теперь, когда маршруты определены, нам нужно сообщить нашему приложению о маршрутах. Для этого загрузите поставщика, который мы экспортировали в предыдущем примере.
Найдите конфигурацию бутстрапа (должно быть в main.ts
, но ваш пробег может отличаться ).
//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));
Настройка маршрутизатора-выхода
Теперь, когда маршрутизатор настроен, и наше приложение знает, как обрабатывать маршруты, нам нужно показать фактические компоненты, которые мы настроили.
Для этого настройте свой HTML-шаблон / файл для своего верхнего уровня (приложение) следующим образом:
//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>
Элемент <router-outlet></router-outlet>
переключит контент, заданный по маршруту. Другим хорошим аспектом этого элемента является то, что он не должен быть единственным элементом в вашем HTML.
Например: Допустим, вам нужна панель инструментов aa на каждой странице, которая остается постоянной между маршрутами, подобно тому, как выглядит Stack Overflow. Вы можете вставить элементы <router-outlet>
под элементами, чтобы изменились только определенные части страницы.
Изменение маршрутов (с использованием шаблонов и директив)
Теперь, когда маршруты настроены, нам нужно каким-то образом изменить маршруты.
В этом примере будет показано, как изменить маршруты с помощью шаблона, но можно изменить маршруты в TypeScript.
Вот один пример (без привязки):
<a routerLink="/home">Home</a>
Если пользователь нажимает на эту ссылку, он будет маршрутизироваться в /home
. Маршрутизатор знает, как обращаться /home
, поэтому он отобразит Home
Component.
Вот пример с привязкой данных:
<a *ngFor="let link of links" [routerLink]="link">{{link}}</a>
Для этого потребуется массив, называемый links
чтобы существовать, поэтому добавьте его в app.ts
:
public links[] = [
'home',
'login'
]
Это будет проходить через массив и добавить элемент <a>
с директивой routerLink
= значение текущего элемента в массиве, создав это:
<a routerLink="home">home</a>
<a routerLink="login">login</a>
Это особенно полезно, если у вас много ссылок или, возможно, ссылки должны постоянно меняться. Мы позволяем Angular обрабатывать занятую работу по добавлению ссылок, просто загружая информацию, которую она требует.
Прямо сейчас links[]
являются статическими, но можно передавать данные из другого источника.
Настройка маршрутов
ПРИМЕЧАНИЕ. Этот пример основан на выпуске 3.0.0.-beta.2 для @ angular / router. На момент написания этой статьи это последняя версия маршрутизатора.
Чтобы использовать маршрутизатор, определите маршруты в новом файле TypeScript, таком как
//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);
В первой строке мы импортируем provideRouter
чтобы мы могли сообщить нашему приложению, какие маршруты находятся на этапе загрузки.
Например, « Home
и Profile
- это всего лишь два компонента. Вам нужно будет импортировать каждый Component
вам нужен, в качестве маршрута.
Затем экспортируйте массив маршрутов.
path
: путь к компоненту. ВАМ НЕ НУЖНО ИСПОЛЬЗОВАТЬ '/ ........ « Угловое будет делать это автоматически
component
: компонент для загрузки при доступе к маршруту
redirectTo
: Необязательно . Если вам необходимо автоматически перенаправить пользователя при доступе к определенному маршруту, поставьте это.
Наконец, мы экспортируем настроенный маршрутизатор. provideRouter
вернет провайдера, который мы можем увеличить, поэтому наше приложение знает, как обращаться с каждым маршрутом.
Контроль доступа к маршруту или от него
Угловой маршрутизатор по умолчанию позволяет осуществлять навигацию по любому маршруту без каких-либо ограничений. Это не всегда желаемое поведение.
В сценарии, когда пользователю может быть разрешено перемещаться по маршруту или от него, для ограничения этого поведения может использоваться Guard Route Guard .
Если ваш сценарий соответствует одному из следующих вариантов, подумайте об использовании Guard Route Guard,
- Пользователь должен пройти аутентификацию для перехода к целевому компоненту.
- Пользователь должен иметь право на переход к целевому компоненту.
- Компонент требует асинхронного запроса перед инициализацией.
- Компонент требует ввода пользователя перед навигацией.
Как работают гвардейцы
Route Guard работают, возвращая логическое значение для управления поведением навигации маршрутизатора. Если true , маршрутизатор продолжит навигацию к целевому компоненту. Если возвращается false , маршрутизатор отклонит навигацию к целевому компоненту.
Маршрутные защитные интерфейсы
Маршрутизатор поддерживает несколько защитных интерфейсов:
- CanActivate : происходит между навигацией по маршруту.
- CanActivateChild : происходит между навигацией маршрута к дочернему маршруту.
- CanDeactivate : происходит при переходе от текущего маршрута.
- CanLoad : происходит между навигацией маршрута к функциональному модулю, загружаемому асинхронно.
- Resolve : используется для выполнения поиска данных до активации маршрута.
Эти интерфейсы могут быть реализованы в вашей защите для предоставления или удаления доступа к определенным процессам навигации.
Синхронные и асинхронные маршруты
Маршрутные охранники позволяют выполнять синхронные и асинхронные операции для условного управления навигацией.
Синхронный охранник маршрута
Синхронный защитник маршрута возвращает логическое значение, например, вычисляя немедленный результат, чтобы условно управлять навигацией.
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
Асинхронный охранник маршрута
Для более сложного поведения защитник маршрута может асинхронно блокировать навигацию. Асинхронный защитник маршрута может возвращать Наблюдаемый или Обещающий.
Это полезно для таких ситуаций, как ожидание ввода пользователем для ответа на вопрос, ожидание успешного сохранения изменений на сервере или ожидание получения данных с удаленного сервера.
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;
});
}
}
Добавить защиту для настройки маршрута
Файл app.routes
Защищенные маршруты могут canActivate
к 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] }
}
Экспортируйте APP_ROUTER_PROVIDERS для использования в начальной загрузке приложения
export const APP_ROUTER_PROVIDERS = [
AuthGuard,
provideRouter(routes)
];
Использовать Guard в бутстрапе приложения
Файл main.ts (или boot.ts )
Рассмотрим приведенные выше примеры:
- Создайте охрану (где создается Guard) и
- Добавьте защиту для настройки маршрута (где Guard настроен для маршрута, затем экспортируется APP_ROUTER_PROVIDERS ),
мы можем подключить бутстрап к Guard следующим образом
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));
Использование ресольверов и гвардейцев
Мы используем currentUser
в конфигурации маршрута, чтобы поймать текущего пользователя при загрузке первой страницы и распознаватель, чтобы сохранить значение currentUser
, который является нашим аутентифицированным пользователем из бэкэнд.
Упрощенная версия нашей реализации выглядит следующим образом:
Вот наш маршрут верхнего уровня:
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
Вот наш 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);
}
}
Вот наш 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);
}
}
Вот наш 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;
}
}