如何拥有路守,通过后路由到辅助路线?

问题描述 投票:0回答:1

我的 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 上重新创建了一个最小的示例。

任何帮助将不胜感激 - 无论是解决这个问题还是告诉我哪里出了问题,这样我就可以自己解决它。

angular angular2-routing angular-router-guards angular-auxiliary-routes
1个回答
0
投票

我试图让它从

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',
      },
    ],
  },
];

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.