Ser*_*dez 5 angular-routing ngrx angular ngrx-store angular-canload
我正在 Angular 9 应用程序中工作,并且仅当我的应用程序状态 (ngrx) 具有属性 != null 时,我才尝试加载(或不加载)特定模块
首先,我的路线中有一个 AuthGuard,但带有 canActivate。所以我希望“仪表板”模块仅在 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'
}];
Run Code Online (Sandbox Code Playgroud)
这是我的 AuthGuard。它 localestorage 没有会话,然后重定向到登录页面。
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我想要用 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;
}
})
);
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做...应用程序会给我错误并仍然加载这两个文件
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做......应用程序永远不会完成加载
{ path: '', canLoad: [ AuthModuleGuard ], loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule) },
Run Code Online (Sandbox Code Playgroud)
这是一个 STACKBLITZ 示例(包括我的文件夹结构)---> https://stackblitz.com/edit/angular-ivy-nasx7r
仅当我的商店中的令牌已设置时,我才需要一种加载仪表板模块(和其他模块)的方法,如果未设置,则重定向到登录。请帮忙
花了一些时间之后,我学到了一些非常有趣的东西:
loadChildren和,则将选择后者childrenif (route.children) {
// The children belong to the same module
return of(new LoadedRouterConfig(route.children, ngModule));
}
if (route.loadChildren) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
这也表明canLoad在这种情况下是多余的:
{
path: '',
component: AppLayoutComponent,
canLoad: [ AuthModuleGuard ],
children: [ ... ]
}
Run Code Online (Sandbox Code Playgroud)
因为这个路由守卫与 一起使用时才有效loadChildren。
你应该注意何时从你的守卫处转向
使用这样的配置:
{
path: '',
component: AppLayoutComponent,
children: [
{
path: '',
loadChildren: () => import('./pages/modules/dashboard/dashboard.module').then(m => m.DashboardModule),
canLoad: [AuthModuleGuard]
}
]
},
Run Code Online (Sandbox Code Playgroud)
还有一个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;
}
})
);
}
Run Code Online (Sandbox Code Playgroud)
你会陷入无限循环。当应用程序首次加载时,它将以深度优先的方式遍历每个配置,并将路径与当前段(最初为)进行比较segments = []。
但请记住,如果路线有children属性,它将遍历每个属性并查看这些段是否与路线匹配。由于子路由有path: '',它将匹配任何段,并且因为它有loadChildren,它将调用canLoad守卫。
最终,将达到这一行:
this.router.navigate(['session/signin']);
return false;
Run Code Online (Sandbox Code Playgroud)
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]
}
]
},
Run Code Online (Sandbox Code Playgroud)
当应用程序加载时,段将是一个空数组,并且因为path: ''匹配任何段组并且该段组[]最初是匹配的,所以将会有一个匹配:
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: {}};
}
Run Code Online (Sandbox Code Playgroud)
这意味着将调用守卫,并且if将到达并this.router.navigate(['session/signin'])调用 的替代块。
下次进行比较时,这些段将(大致)['session', 'signin']并且不会匹配,因为返回的是:
{matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}}
Run Code Online (Sandbox Code Playgroud)
如果没有匹配,它将继续搜索,直到找到东西,但不会再次调用守卫。
| 归档时间: |
|
| 查看次数: |
1716 次 |
| 最近记录: |