使用 NgRx 在子路由中加载 canLoad
canLoad in children routes using NgRx
我在 Angular 9 应用程序中工作,并且仅当我的应用程序状态 (ngrx) 具有 属性 != null 时,我才尝试加载(或不加载)特定模块
首先,我的路线中有一个 AuthGuard,但带有 canActivate。
所以我希望 'dashboard' 模块仅在 mt AppState 具有令牌时加载
这是我的路线文件
const routes: Routes = [
{
path: '',
component: AppLayoutComponent,
canActivate: [ AuthGuard ],
children: [
{ path: '', loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule) }
]
},
{
path: '',
component: AuthLayoutComponent,
children: [
{ path: 'session', loadChildren: () => import('./pages/modules/session/session.module').then(m => m.SessionModule) }
]
},
{
path: '**',
redirectTo: 'session/not-found'
}];
这是我的 AuthGuard。它的本地存储没有会话,然后重定向到登录页面。
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router, public authService: AuthService) {}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (localStorage.getItem('session')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['session/signin']);
return false;
}
}
这就是我想用 AuthModuleGuard 中的 canLoad 做的事情,但这不起作用
public canLoad(): Observable<boolean> {
return this.store.select('session').pipe(
take(1),
map((authstate) => {
console.log('Token status', authstate.token);
if (authstate.token !== null) {
return true;
} else {
this.router.navigate(['session/signin']);
return false;
}
})
);
}
如果我这样做...应用程序会给我错误,但仍会加载两个文件
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
如果我这样做......应用程序永远不会完成加载
{ path: '', canLoad: [ AuthModuleGuard ], loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule) },
这是一个 STACKBLITZ 示例(包括我的文件夹结构)---> https://stackblitz.com/edit/angular-ivy-nasx7r
我需要一种方法来加载仪表板模块(和其他模块),仅当我商店中的令牌已设置时,如果未设置,则重定向到登录。请帮忙
在这方面花了一些时间之后,我学到了一些非常有趣的东西:
- 如果您的路线配置中同时有
loadChildren
和 children
,the latter will be chosen
if (route.children) {
// The children belong to the same module
return of(new LoadedRouterConfig(route.children, ngModule));
}
if (route.loadChildren) { /* ... */ }
这也表示 canLoad
在这种情况下是多余的:
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
因为这个路由守卫和loadChildren
一起使用才有效。
你应该注意什么时候从你的守卫重定向
配置如下:
{
path: '',
component: AppLayoutComponent,
children: [
{
path: '',
loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule),
canLoad: [AuthModuleGuard]
}
]
},
还有一个 canLoad
这样的守卫:
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> {
return this.store.select('session').pipe(
take(1),
map((authstate) => {
console.log('Token status', authstate.token);
if (authstate.token !== null) {
return true;
} else {
this.router.navigate(['session/signin']);
return false;
}
})
);
}
您将进入无限循环。当应用程序首次加载时,它将以 深度优先 的方式遍历每个配置,并将 path 与当前段进行比较(最初, segments = []
)。
但请记住,如果一条路线有 children
属性,它将遍历每个路线并查看 路段是否与路线 匹配。由于子路由有 path: ''
,它将匹配 任何段 并且因为它有 loadChildren
,它将调用 canLoad
守卫。
最终会到达这一行:
this.router.navigate(['session/signin']);
return false;
this.router.navigate(['session/signin']);
表示重定向,即重复上述步骤。
我想到的解决方案是在你的子路由中添加一个pathMatch: 'full'
:
{
path: '',
component: AppLayoutComponent,
children: [
{
path: '',
pathMatch: 'full',
loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule),
canLoad: [AuthModuleGuard]
}
]
},
应用程序加载时,段 将是一个空数组,因为path: ''
匹配任何段组并且该组段最初是 []
,there will be a match:
if (route.path === '') {
if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) {
return {matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}
return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}
这意味着将调用守卫并且将到达 if
的替代块并调用 this.router.navigate(['session/signin'])
。
下次进行比较时,段将(大致)为 ['session', 'signin']
并且不会有匹配项,因为返回的是:
{matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}}
如果没有匹配出现,它将继续搜索直到找到某些东西,但不会再次调用守卫。
我在 Angular 9 应用程序中工作,并且仅当我的应用程序状态 (ngrx) 具有 属性 != null 时,我才尝试加载(或不加载)特定模块
首先,我的路线中有一个 AuthGuard,但带有 canActivate。 所以我希望 'dashboard' 模块仅在 mt AppState 具有令牌时加载
这是我的路线文件
const routes: Routes = [
{
path: '',
component: AppLayoutComponent,
canActivate: [ AuthGuard ],
children: [
{ path: '', loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule) }
]
},
{
path: '',
component: AuthLayoutComponent,
children: [
{ path: 'session', loadChildren: () => import('./pages/modules/session/session.module').then(m => m.SessionModule) }
]
},
{
path: '**',
redirectTo: 'session/not-found'
}];
这是我的 AuthGuard。它的本地存储没有会话,然后重定向到登录页面。
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router, public authService: AuthService) {}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (localStorage.getItem('session')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['session/signin']);
return false;
}
}
这就是我想用 AuthModuleGuard 中的 canLoad 做的事情,但这不起作用
public canLoad(): Observable<boolean> {
return this.store.select('session').pipe(
take(1),
map((authstate) => {
console.log('Token status', authstate.token);
if (authstate.token !== null) {
return true;
} else {
this.router.navigate(['session/signin']);
return false;
}
})
);
}
如果我这样做...应用程序会给我错误,但仍会加载两个文件
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
如果我这样做......应用程序永远不会完成加载
{ path: '', canLoad: [ AuthModuleGuard ], loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule) },
这是一个 STACKBLITZ 示例(包括我的文件夹结构)---> https://stackblitz.com/edit/angular-ivy-nasx7r
我需要一种方法来加载仪表板模块(和其他模块),仅当我商店中的令牌已设置时,如果未设置,则重定向到登录。请帮忙
在这方面花了一些时间之后,我学到了一些非常有趣的东西:
- 如果您的路线配置中同时有
loadChildren
和children
,the latter will be chosen
if (route.children) {
// The children belong to the same module
return of(new LoadedRouterConfig(route.children, ngModule));
}
if (route.loadChildren) { /* ... */ }
这也表示 canLoad
在这种情况下是多余的:
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
因为这个路由守卫和loadChildren
一起使用才有效。
你应该注意什么时候从你的守卫重定向
配置如下:
{
path: '',
component: AppLayoutComponent,
children: [
{
path: '',
loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule),
canLoad: [AuthModuleGuard]
}
]
},
还有一个 canLoad
这样的守卫:
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> {
return this.store.select('session').pipe(
take(1),
map((authstate) => {
console.log('Token status', authstate.token);
if (authstate.token !== null) {
return true;
} else {
this.router.navigate(['session/signin']);
return false;
}
})
);
}
您将进入无限循环。当应用程序首次加载时,它将以 深度优先 的方式遍历每个配置,并将 path 与当前段进行比较(最初, segments = []
)。
但请记住,如果一条路线有 children
属性,它将遍历每个路线并查看 路段是否与路线 匹配。由于子路由有 path: ''
,它将匹配 任何段 并且因为它有 loadChildren
,它将调用 canLoad
守卫。
最终会到达这一行:
this.router.navigate(['session/signin']);
return false;
this.router.navigate(['session/signin']);
表示重定向,即重复上述步骤。
我想到的解决方案是在你的子路由中添加一个pathMatch: 'full'
:
{
path: '',
component: AppLayoutComponent,
children: [
{
path: '',
pathMatch: 'full',
loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule),
canLoad: [AuthModuleGuard]
}
]
},
应用程序加载时,段 将是一个空数组,因为path: ''
匹配任何段组并且该组段最初是 []
,there will be a match:
if (route.path === '') {
if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) {
return {matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}
return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}
这意味着将调用守卫并且将到达 if
的替代块并调用 this.router.navigate(['session/signin'])
。
下次进行比较时,段将(大致)为 ['session', 'signin']
并且不会有匹配项,因为返回的是:
{matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}}
如果没有匹配出现,它将继续搜索直到找到某些东西,但不会再次调用守卫。