【问题标题】:Conditionally load module on the empty path in Angular router有条件地在 Angular 路由器的空路径上加载模块
【发布时间】:2019-05-25 00:22:41
【问题描述】:

我正在尝试为未经身份验证的访问者加载我的应用主页。

const routes: Routes = [
    { path: '', loadChildren: './home/home.module#HomeModule' }
...

经过身份验证的用户应该通过该模块获取他们的提要,也在空路径上。

{ path: '', loadChildren: './feed/feed.module#FeedModule', canActivate: [IsAuthenticationGuard] },
{ path: '', loadChildren: './home/home.module#HomeModule', canActivate: [NoAuthenticationGuard] },

我预计IsAuthenticationGuard 会失败并加载默认的主组件。

相反,它会下载 feed 模块包(显示在网络选项卡中),但不会在路由器插座中加载任何内容。很混乱。

如何在空路径上进行条件路由(基于守卫或其他)?

更新:这里是应要求提供的警卫

@Injectable()
export class IsAuthenticationGuard implements CanActivate {
    constructor(
        private authenticationService: AuthenticationService
    ) { }

    public canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ): Observable<boolean> {
        return this.authenticationService.isAuthenticated.pipe(take(1), map((isAuthentication) => {
            return isAuthentication;
        }));
    }
}

我研究了新的urlTree,现在您可以通过路由重定向而不是在守卫内重定向,这很酷。 但是,如果您尝试将相同的路由与不同的模块一起使用,则重定向似乎不适用。如果有办法,请纠正我。

【问题讨论】:

  • 您需要使用matchers。检查此以获取线索:medium.com/@lenseg1/…
  • 请向我们展示你的警卫
  • 你不能放两个空路径,你应该放一个空并给另一个一个url,然后在守卫中,你可以通过router.navigate进行重定向
  • 虽然此功能不存在,但有一个功能请求:github.com/angular/angular/issues/12088
  • 解决方案:您可以通过创建路由matcher 来做到这一点。 代码: 我在这里回答:stackoverflow.com/a/67422797/14389830 注意: 在链接的答案中有一个工作示例,并链接了相关的 blogs 以获取详细信息和演练怎么做。

标签: javascript angular module routing


【解决方案1】:

事实证明,在 Ivy 之前,这基本上是(安全地)不可能的。现在在 Angular 9/10 中,我们可以很容易地在没有路由器的情况下延迟加载功能模块。

StackBlitz
V13 StackBlitz Update

@Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
})
export class AppComponent implements OnInit  {
    @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

    constructor( 
        private compiler: Compiler,
        private injector: Injector
    ){  }

    public ngOnInit(): void {
        if (loggedin) {
            this.loadModule(await import('./lazy/lazy.module').then(m => m.LazyModule));
        } else {
            this.loadModule(await import('./lazy2/lazy2.module').then(m => m.Lazy2Module));
        }
    }

    async loadModule(module: Type<any>) {
        let ref;
        try {
            this.container.clear();

            // Angular < 13 
            const moduleFactory = await this.compiler.compileModuleAsync(module);
            const moduleRef: any = moduleFactory.create(this.injector);
            const componentFactory = moduleRef.instance.resolveComponent(); // ASSERTION ERROR
            ref = this.container.createComponent(componentFactory, null, moduleRef.injector);

            // Angular 13 update
            const moduleRef = createNgModuleRef(module, this.injector);
            const componentFactory = moduleRef.instance.resolveComponent();
            ref = container.createComponent(
                componentFactory,
                undefined,
                moduleRef.injector
            );

        } catch (e) {
            console.error(e);
        }
            return ref;
        }
    }

【讨论】:

    【解决方案2】:

    我相信你打算通过守卫实现的目标是不可能的。 Angular 从上到下搜索路由数组,一旦找到路径匹配,就会加载相应的模块/组件。在您的情况下,{ path: '', loadChildren: './feed/feed.module#FeedModule', canActivate: [IsAuthenticationGuard] } 是一个 url 路径匹配,因此 Angular 会加载 Feed 模块,但是由于防护返回失败,因此不会显示任何内容。它甚至没有继续检查下面行的 url 匹配。

    相反,你可以做的是,

    1. 将路由更改为{ path: '', loadChildren:'./home/home.module#HomeModule', canActivate: [IsAuthenticationGuard] },
    2. 如果用户成功通过身份验证,则导航到 feed 模块。关注 this thread 以获取有关如何执行此操作的更多线索。

    我希望这能解决你的目的。

    【讨论】:

    • 谢谢MM!是的,您可以从警卫内部定义重定向。尤其是现在在 7.2 中使用新的 UrlTree 它更容易。但这仍然是一个常见的重定向。我说的是根据身份验证状态利用相同的路径。
    【解决方案3】:

    试试这个:

    const routes: Routes = [
      { path: '', redirectTo: condition ? 'home' : 'feed', pathMatch: 'full' },
      { path: 'home', component: HomeComponent },
      { path: 'feed', component: FeedComponent },
      { path: '*', redirectTo: 'home', pathMatch: 'full' },
    ];

    这不是直接基于Guards,但你应该能够让你的Guard return 作为条件

    【讨论】:

      【解决方案4】:

      在我看来,你做错了几件事。

      1. 您不应该使用相同的路径定义两条路由。
      2. 在你的保护下,地图毫无意义。只要您的服务方法返回Observable&lt;boolean&gt;,您就不需要映射它的值。
      3. 如果你没有返回真值,你也需要小心,你需要导航到另一个模块的路径。为此,您需要实现一些其他逻辑来判断用户是否已登录。

      看看官方的角度路由指南here。有很多有用的信息可以帮助你。尤其是这些:

      编辑 2018/12/27

      所以如果问题是如何在同一路径上有条件地加载两个功能模块

      答案是,根据我的经验,你不能。

      【讨论】:

      • 非常感谢您的回答!但我知道如何做到这一切。重定向也不适用。问题是如何有条件地在空路径上加载功能模块。
      • 您是否检查了启用调试时发生了什么?它可能会对您的设置发生的情况有所了解。
      • 我认为你可能是正确的,如果没有像提到的 nircraft 那样对路由器进行黑客攻击,就无法做到这一点。
      • 使未经授权的路径与空路径不同。在您的 Guard 上,您可以在返回之前处理身份验证响应。因此,如果这是错误的,您可以使用路由器导航到未经授权的路径。
      猜你喜欢
      • 2021-07-26
      • 2020-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      • 2020-07-26
      • 1970-01-01
      相关资源
      最近更新 更多