我的 Angular 应用程序有一个部分,只能通过发送到用户电子邮件(Docusign 类型的东西)的生成链接来访问。它通过功能模块与应用程序的其余部分分开,具有自己的路线,并延迟加载到主
app.routes.ts
中。
用户将获得类似
{domain}.com/sign-doc/document/:id
的链接,其中 :id 将是唯一的字符串。
我想像这样设置功能模块路由结构
export const routes: Routes = [
{
path: 'document/:id',
component: SignDocumentComponent,
canActivate: [isValidDocumentIdGuard],
children: [
{
path: 'metadata',
component: DocumentMetadataComponent,
outlet: 'sign'
},
{
path: 'confirm-identity',
component: ConfirmIdentityComponent,
outlet: 'sign'
},
{
path: 'view-document',
canActivateChild: [ identityConfirmedGuard ],
children: [
{
path: 'signed',
component: ViewAndSignComponent,
outlet: 'sign'
},
{
path: 'unsigned',
component: ViewAndSignComponent,
outlet: 'sign'
},
],
},
],
},
{
path: 'contact-admin',
component: ContactAdminComponent,
},
];
SignDocumentComponent
模板如下所示:
<router-outlet name="sign" />
<app-session-extender />
app.routes.ts
看起来像这样:
export const routes: Routes = [
/** other routes */,
{
path: 'sign-doc',
loadChildren: () => import('./sign-doc/sign.module').then(x => x.SignDocumentModule),
}
];
我有一个路由守卫,
isValidDocumentIdGuard
,它将异步检查提供的 ID 是否是我们有文档的 ID,如果有效,则应将辅助插座路由到 metadata
,否则应将主插座重定向到contact-admin
路径。我这样做的方法是让守卫返回createUrlTreeFromSnapshot(routeSnapshot, [{ outlets: { sign: ['metadata'] } }])
如果成功的话。
问题是我似乎陷入了进入
sign-doc/document/:id/(sign:metadata)
的无限循环中,大概是因为它通过守卫将自己路由回来。
我在 StackBlitz 上重新创建了一个最小的示例。
任何帮助将不胜感激 - 无论是解决这个问题还是告诉我哪里出了问题,这样我就可以自己解决它。
我试图让它从
guard
开始工作,但它继续导致无限循环。
我尝试了另一种方法,使用角度的
redirectFunction
(相当新),这将构造完整的URL并触发导航,这里它重定向到辅助路线,没有任何循环。
export const redirectToFn: RedirectFunction = (redirectData: any) => {
const router = inject(Router);
return router.createUrlTree([
`/xyz/${redirectData.params.id}`,
{ outlets: { child: ['def'] } },
]);
};
代码非常简单,我们使用
router.createUrlTree
导航到完整路线+辅助路线。我们使用 inject
来访问路由器。
我们可以在
redirectTo
属性上指定此函数来触发通配符路由。
export const routes: Routes = [
{
path: ':id',
component: XyzComponent,
canActivate: [validIdGuard],
children: [
{
path: 'def',
outlet: 'child',
component: DefComponent,
},
{
path: '**',
redirectTo: redirectToFn,
pathMatch: 'full',
},
],
},
];
最后,我们让守卫返回一个布尔值而不是导航操作。
export const validIdGuard: CanActivateFn = async (route, state) => {
const id = route.params['id'] as string;
const valid = await validId(id);
if (valid) {
console.log('asdf', route, state);
return true;
}
import { CanActivateFn } from '@angular/router';
export const validIdGuard: CanActivateFn = async (route, state) => {
const id = route.params['id'] as string;
const valid = await validId(id);
if (valid) {
console.log('asdf', route, state);
return true;
}
return false; // redirect to error page in real deal
};
async function validId(id: string): Promise<boolean> {
return true;
}
import {
RedirectFunction,
Routes,
Router,
ActivatedRoute,
} from '@angular/router';
import { XyzComponent } from './xyz.component';
import { DefComponent } from './def/def.component';
import { validIdGuard } from './guards/redirect-guard';
import { inject } from '@angular/core';
export const redirectToFn: RedirectFunction = (redirectData: any) => {
const route = inject(ActivatedRoute);
const router = inject(Router);
return router.createUrlTree([
`/xyz/${redirectData.params.id}`,
{ outlets: { child: ['def'] } },
]);
};
export const routes: Routes = [
{
path: ':id',
component: XyzComponent,
canActivate: [validIdGuard],
children: [
{
path: 'def',
outlet: 'child',
component: DefComponent,
},
{
path: '**',
redirectTo: redirectToFn,
pathMatch: 'full',
},
],
},
];