【问题标题】:Conditionally Load Different Modules on the Same Path in Angular在 Angular 的同一路径上有条件地加载不同的模块
【发布时间】:2021-07-26 22:21:53
【问题描述】:

我有一个多用户 Angular 应用程序,每个用户都有一个模块(因为他们有完全不同的可访问页面),如下所示:

  • app.module.ts
  • app-routing.module.ts
  • 登录/
    • login.component.ts
  • 管理员/
    • 页数/
      • 用户管理/
      • 配置/
    • admin.module.ts
    • admin-routing.module.ts
  • 用户/
    • 页数/
      • 任务管理/
      • 配置/
    • user.module.ts
    • user-routing.module.ts
  • 客人/
    • 页数/
    • guest.module.ts
    • guest-routing.module.ts

从登录页面(来自 app-routing 的/login),我想根据用户提供的凭据重定向到每个模块,但 NOT 使用像 /user @987654324 这样的子路由@或/guest

相反,当管理员登录时,我希望重置 URL。因此,例如,管理员不应该看到路径/admin/user-management/admin/configuration;它只是访问/user-management/configuration

这可能吗?如果我有 adminuser/configuration 路由会不会有问题?

编辑:这是Stackblitz working example。登录后查看 URL 路由。

编辑 2: 在 Stackblitz 示例中,您可以在 master 上看到原始问题,在 solution 分支上看到工作解决方案。

【问题讨论】:

  • 你必须去设置路由器保护?
  • 我实现了一个auth.guard.ts 来限制没有特定角色的用户无法访问的页面,但问题在于 URL 路由本身,而不是对它的访问
  • 如果角色是管理员,那么您可以使用 canLoad、canActivate、guard 来不加载 URL
  • 你能举个例子吗?我已经使用 canActivate 让管理员只能访问管理员路由,但这不是问题。问题是,每当我加载路由子模块(UserModuleAdminModuleGuestModule)时,我都必须在子路由下进行(分别为/users/admin/guest)。但我不想要这种行为。我想加载一个子模块并在根路由(/)下使用它的路由
  • 然后将所有这些子模块放到父路径,它将作为父@GusSL加载

标签: angular angular2-routing


【解决方案1】:

解决方案:

经过大量调查,我发现可以通过创建路由matcher来完成。

代码:

我设法使它与您的代码一起工作。这是工作示例: https://stackblitz.com/edit/angular2-routing-test-qj4geu?file=src/app/user/user.component.html

这是app-routing.module.ts上的相关代码:

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  {
    matcher: url => {
      const user_type = localStorage.getItem('user_type');
      if (user_type === 'user') {
        return url.length ? { consumed: [] } : { consumed: url };
      }
      return null;
    },
    loadChildren: () => import('./user/user.module').then(m => m.UserModule)
  },
  {
    matcher: url => {
      const user_type = localStorage.getItem('user_type');
      if (user_type === 'admin') {
        return url.length ? { consumed: [] } : { consumed: url };
      }
      return null;
    },
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  },
  {
    matcher: url => {
      const user_type = localStorage.getItem('user_type');
      if (user_type === 'guest') {
        return url.length ? { consumed: [] } : { consumed: url };
      }
      return null;
    },
    loadChildren: () => import('./guest/guest.module').then(m => m.GuestModule)
  },
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'login'
  }
];

注意:

如这里所说:https://github.com/angular/angular/issues/23866#issuecomment-388527483,当我们使用路由matcher 时,我们需要指定url 的哪一部分被matcher 函数消耗,剩余部分将被发送到嵌套路由器。

博客:

这里有两篇博文,其中包含详细的详细信息和操作方法:

博客1:https://medium.com/@brandontroberts/custom-route-matching-with-the-angular-router-fbdd48665483

博客2:https://medium.com/@lenseg1/loading-different-angular-modules-or-components-on-routes-with-same-path-2bb9ba4b6566

【讨论】:

  • 问题是模块admin是在/admin路由下加载的,所有子路由都附加/admin。请查看更新问题中的 Stackblitz。
  • 主路由按预期工作!似乎 localStorage 是要走的路,因为不必注入全局身份验证服务。但有一件事,子路由停止工作,甚至在 URL 中手动输入。登录时似乎与任何子路由都不匹配,只是跳转到子模块路由模块中的最后一个('')。
  • 经过几个小时的调查,我用几行代码解决了这个错误。我更新了工作示例,现在所有子路线也可以工作。可以查一下吗?
  • 效果很好!但是,我对解决方案进行了一些改进以减少重复性,使模块选择在一个自定义匹配的路线中,但本质上它与您的相同。非常感谢!
  • 嘿,我看到你建议编辑。把所有东西都放在一条路线上是个好主意matcher。但是,当我尝试时,您建议的代码不起作用。它在用户第一次登录时工作,但如果您注销并以其他不同类型的用户身份再次登录,则会加载先前用户的模块。在这里查看:loom.com/share/f9477b5c08b44652b1603c0a999d03ce
【解决方案2】:

我猜你使用延迟加载配置看起来像这样:

  {
    path: 'config',
    loadChildren: () => import('./pages/userConfig/userConfig.module').then( m => m.UserConfigPageModule),
  },

您可以将箭头函数转换为普通函数并执行例如一个 switch 语句来决定你想加载什么模块:

  {
    path: 'config',
    loadChildren: () => {
      switch(userType) {
        case 'IsAdmin':
          return import('./pages/adminConfig/adminConfig.module').then( m => m.AdminConfigPageModule);
        case 'IsUser':
          return import('./pages/userConfig/userConfig.module').then( m => m.UserConfigPageModule);
        default:
          return import('./pages/guestConfig/guestConfig.module').then( m => m.GuestConfigPageModule);
      }
    },
    canActivate: [ConfigGuard],
  },

工作stackblitz

注意:
注销后,您需要刷新 stackblitz 视图,否则会出现故障。我稍后会研究它。

【讨论】:

  • 这可能是解决方案。我在全局服务中使用 BehaviorSubject 来获取当前用户。如何在声明路由的 app-routing.module 中注入服务?另外,请看一下 Stackblitz,我更新了问题。
  • @GusSL 查看堆栈闪电战
  • 它可以工作,但是当注销并再次登录时,它会加载最后一个模块。无论如何,switch case的想法对构建上面的最终答案有很大帮助。谢谢!
猜你喜欢
  • 2019-05-25
  • 2018-05-14
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 2019-04-22
  • 2019-09-03
  • 1970-01-01
相关资源
最近更新 更多