
CanLoad now defines UrlSegment[] as a second parameter of the function. Users can store the initial url segments and refer to them later, e.g. to go back to the original url after authentication via router.navigate(urlSegments). Existing code still works as before because the second function parameter does not have to be defined. Closes #12411 PR Close #13127
379 lines
8.6 KiB
TypeScript
379 lines
8.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Observable} from 'rxjs';
|
|
|
|
import {Route} from './config';
|
|
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
|
|
import {UrlSegment} from './url_tree';
|
|
|
|
|
|
/**
|
|
* @description
|
|
*
|
|
* Interface that a class can implement to be a guard deciding if a route can be activated.
|
|
*
|
|
* ```
|
|
* class UserToken {}
|
|
* class Permissions {
|
|
* canActivate(user: UserToken, id: string): boolean {
|
|
* return true;
|
|
* }
|
|
* }
|
|
*
|
|
* @Injectable()
|
|
* class CanActivateTeam implements CanActivate {
|
|
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
|
|
*
|
|
* canActivate(
|
|
* route: ActivatedRouteSnapshot,
|
|
* state: RouterStateSnapshot
|
|
* ): Observable<boolean>|Promise<boolean>|boolean {
|
|
* return this.permissions.canActivate(this.currentUser, route.params.id);
|
|
* }
|
|
* }
|
|
*
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* canActivate: [CanActivateTeam]
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [CanActivateTeam, UserToken, Permissions]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
* You can alternatively provide a function with the `canActivate` signature:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* canActivate: ['canActivateTeam']
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [
|
|
* {
|
|
* provide: 'canActivateTeam',
|
|
* useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => true
|
|
* }
|
|
* ]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
*
|
|
*/
|
|
export interface CanActivate {
|
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
|
|
Observable<boolean>|Promise<boolean>|boolean;
|
|
}
|
|
|
|
/**
|
|
* @description
|
|
*
|
|
* Interface that a class can implement to be a guard deciding if a child route can be activated.
|
|
*
|
|
* ```
|
|
* class UserToken {}
|
|
* class Permissions {
|
|
* canActivate(user: UserToken, id: string): boolean {
|
|
* return true;
|
|
* }
|
|
* }
|
|
*
|
|
* @Injectable()
|
|
* class CanActivateTeam implements CanActivateChild {
|
|
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
|
|
*
|
|
* canActivateChild(
|
|
* route: ActivatedRouteSnapshot,
|
|
* state: RouterStateSnapshot
|
|
* ): Observable<boolean>|Promise<boolean>|boolean {
|
|
* return this.permissions.canActivate(this.currentUser, route.params.id);
|
|
* }
|
|
* }
|
|
*
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'root',
|
|
* canActivateChild: [CanActivateTeam],
|
|
* children: [
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: Team
|
|
* }
|
|
* ]
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [CanActivateTeam, UserToken, Permissions]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
* You can alternatively provide a function with the `canActivateChild` signature:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'root',
|
|
* canActivateChild: ['canActivateTeam'],
|
|
* children: [
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: Team
|
|
* }
|
|
* ]
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [
|
|
* {
|
|
* provide: 'canActivateTeam',
|
|
* useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => true
|
|
* }
|
|
* ]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
*
|
|
*/
|
|
export interface CanActivateChild {
|
|
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot):
|
|
Observable<boolean>|Promise<boolean>|boolean;
|
|
}
|
|
|
|
/**
|
|
* @description
|
|
*
|
|
* Interface that a class can implement to be a guard deciding if a route can be deactivated.
|
|
*
|
|
* ```
|
|
* class UserToken {}
|
|
* class Permissions {
|
|
* canDeactivate(user: UserToken, id: string): boolean {
|
|
* return true;
|
|
* }
|
|
* }
|
|
*
|
|
* @Injectable()
|
|
* class CanDeactivateTeam implements CanDeactivate<TeamComponent> {
|
|
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
|
|
*
|
|
* canDeactivate(
|
|
* component: TeamComponent,
|
|
* currentRoute: ActivatedRouteSnapshot,
|
|
* currentState: RouterStateSnapshot,
|
|
* nextState: RouterStateSnapshot
|
|
* ): Observable<boolean>|Promise<boolean>|boolean {
|
|
* return this.permissions.canDeactivate(this.currentUser, route.params.id);
|
|
* }
|
|
* }
|
|
*
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* canDeactivate: [CanDeactivateTeam]
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [CanDeactivateTeam, UserToken, Permissions]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
* You can alternatively provide a function with the `canDeactivate` signature:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* canDeactivate: ['canDeactivateTeam']
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [
|
|
* {
|
|
* provide: 'canDeactivateTeam',
|
|
* useValue: (component: TeamComponent, currentRoute: ActivatedRouteSnapshot, currentState:
|
|
* RouterStateSnapshot, nextState: RouterStateSnapshot) => true
|
|
* }
|
|
* ]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
*
|
|
*/
|
|
export interface CanDeactivate<T> {
|
|
canDeactivate(
|
|
component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
|
|
nextState?: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean;
|
|
}
|
|
|
|
/**
|
|
* @description
|
|
*
|
|
* Interface that class can implement to be a data provider.
|
|
*
|
|
* ```
|
|
* class Backend {
|
|
* fetchTeam(id: string) {
|
|
* return 'someTeam';
|
|
* }
|
|
* }
|
|
*
|
|
* @Injectable()
|
|
* class TeamResolver implements Resolve<Team> {
|
|
* constructor(private backend: Backend) {}
|
|
*
|
|
* resolve(
|
|
* route: ActivatedRouteSnapshot,
|
|
* state: RouterStateSnapshot
|
|
* ): Observable<any>|Promise<any>|any {
|
|
* return this.backend.fetchTeam(route.params.id);
|
|
* }
|
|
* }
|
|
*
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* resolve: {
|
|
* team: TeamResolver
|
|
* }
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [TeamResolver]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
* You can alternatively provide a function with the `resolve` signature:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* resolve: {
|
|
* team: 'teamResolver'
|
|
* }
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [
|
|
* {
|
|
* provide: 'teamResolver',
|
|
* useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => 'team'
|
|
* }
|
|
* ]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
*/
|
|
export interface Resolve<T> {
|
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T>|Promise<T>|T;
|
|
}
|
|
|
|
|
|
/**
|
|
* @description
|
|
*
|
|
* Interface that a class can implement to be a guard deciding if a children can be loaded.
|
|
*
|
|
* ```
|
|
* class UserToken {}
|
|
* class Permissions {
|
|
* canLoadChildren(user: UserToken, id: string, segments: UrlSegment[]): boolean {
|
|
* return true;
|
|
* }
|
|
* }
|
|
*
|
|
* @Injectable()
|
|
* class CanLoadTeamSection implements CanLoad {
|
|
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
|
|
*
|
|
* canLoad(route: Route, segments: UrlSegment[]): Observable<boolean>|Promise<boolean>|boolean {
|
|
* return this.permissions.canLoadChildren(this.currentUser, route, segments);
|
|
* }
|
|
* }
|
|
*
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* loadChildren: 'team.js',
|
|
* canLoad: [CanLoadTeamSection]
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [CanLoadTeamSection, UserToken, Permissions]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
* You can alternatively provide a function with the `canLoad` signature:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [
|
|
* RouterModule.forRoot([
|
|
* {
|
|
* path: 'team/:id',
|
|
* component: TeamCmp,
|
|
* loadChildren: 'team.js',
|
|
* canLoad: ['canLoadTeamSection']
|
|
* }
|
|
* ])
|
|
* ],
|
|
* providers: [
|
|
* {
|
|
* provide: 'canLoadTeamSection',
|
|
* useValue: (route: Route, segments: UrlSegment[]) => true
|
|
* }
|
|
* ]
|
|
* })
|
|
* class AppModule {}
|
|
* ```
|
|
*
|
|
*
|
|
*/
|
|
export interface CanLoad {
|
|
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean>|Promise<boolean>|boolean;
|
|
}
|