【问题标题】:Angular: How to route different modules on the same path depending on serviceAngular:如何根据服务在同一路径上路由不同的模块
【发布时间】:2022-01-20 11:36:37
【问题描述】:

想象一个服务ABService 有一个方法isAResponsible: () => boolean 和两个模块:AModuleBModule

问题是:是否可以根据isAResponsible 返回的内容在AModuleBModule 之间切换?如果isAResponsible 的值发生变化,我们如何“重新路由”并重新渲染? ABService 可能对其他服务有多个依赖项,因此最好以某种方式使用 DI 系统。

示例: 如果感兴趣的路由是/aorb 并且ABService.isAResponsible 返回true,那么我们希望路由AModule。如果ABService.isAResponsible 返回false 但是我们希望BModule 管理进一步的路由。请注意,一切都应该发生在 shared 路线上。

我用警卫和canActivate/canLoad试过但没有成功:

app.module.ts

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { AorBActivateGuard } from './aorb-activate.guard';
import { ABService } from './ab.service';

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: 'aorb',
        canActivate: [AorBActivateGuard],
        loadChildren: () => import('./a/a.module').then((m) => m.AModule),
      },
      {
        path: 'aorb',
        loadChildren: () => import('./b/b.module').then((m) => m.BModule),
      },
    ]),
  ],
  providers: [AorBActivateGuard, ABService],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
})
export class AppModule {}

ab.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class ABService {
  private aIsResponsible = true;

  constructor() {}

  switch() {
    this.aIsResponsible = !this.aIsResponsible;
  }

  isAResponsible() {
    return this.aIsResponsible;
  }
}

aorb-activate.guard.ts

import { Injectable } from '@angular/core';
import {
  CanActivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
import { ABService } from './ab.service';

@Injectable()
export class AorBActivateGuard implements CanActivate {
  constructor(private abService: ABService) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    return this.abService.isAResponsible();
  }
}

【问题讨论】:

    标签: angular module routes


    【解决方案1】:

    可以在AppModule 中注入ABService 并监听来自ABService 的变化。每次发生变化时,我们都可以重新配置(=切换模块)路由器并让它导航相同的路由。通过这种方式,我们总是加载了负责的模块。

    [...]
    @NgModule({
      imports: [
        BrowserModule,
        RouterModule.forRoot([], {
          initialNavigation: 'disabled',
        }),
      ],
      providers: [ABService, BooleanStorageService],
      declarations: [AppComponent],
      bootstrap: [AppComponent],
    })
    export class AppModule {
      constructor(private router: Router, private abService: ABService) {
        abService.onABChange.subscribe(this.resetRouterConfig(true).bind(this));
        this.resetRouterConfig(false)();
        this.router.initialNavigation();
      }
    
      reloadCurrentRoute() {
        const currentUrl = this.router.url;
        this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
          this.router.navigate([currentUrl]);
        });
      }
    
      resetRouterConfig(refresh: boolean) {
        return () => {
          const constructedConfig = [
            {
              path: '',
              pathMatch: 'full',
              redirectTo: 'aorb',
            },
            {
              path: 'aorb',
              loadChildren: () => {
                if (this.abService.isAResponsible()) {
                  return import('./a/a.module').then((m) => m.AModule);
                } else {
                  return import('./b/b.module').then((m) => m.BModule);
                }
              },
            },
          ];
    
          this.router.resetConfig(constructedConfig);
    
          if (refresh) this.reloadCurrentRoute();
        };
      }
    }
    

    您可以找到一个工作示例here

    【讨论】:

      【解决方案2】:

      你可以试试这个,我刚刚在本地检查过它可以工作,只是换一种方式思考,你就有了解决方案:)

      import { NgModule } from '@angular/core';
      import { RouterModule } from '@angular/router';
      import { BrowserModule } from '@angular/platform-browser';
      
      import { AppComponent } from './app.component';
      import { AorBActivateGuard } from './aorb-activate.guard';
      import { ABService } from './ab.service';
      
      @NgModule({
        imports: [
          BrowserModule,
          RouterModule.forRoot([
            {
              path: 'aorb',
              loadChildren: () => {
                if ((new ABService()).isAResponsible()){
                  return import('./a/a.module').then((m) => m.AModule)
                } else {
                  return import('./b/b.module').then((m) => m.BModule)
                }
              },
            },
          ]),
        ],
        providers: [AorBActivateGuard, ABService],
        declarations: [AppComponent],
        bootstrap: [AppComponent],
      })
      export class AppModule {}
      

      【讨论】:

      • 感谢您的回答!我认为我在问题中的场景有点过于简单,因为ABService 可能有几个我们不想管理的依赖项。我已经更新了要求 DI 的问题。也许我们可以调整这个解决方案,让 Angular 注入 ABService?我只知道课堂层面的 DI。
      • 您的服务也是一个类,您可以轻松创建它的实例,然后调用它的具体方法,也许您可​​以查看 Angular 如何创建任何服务的实例并在模块?不确定,但这只是一个想法
      猜你喜欢
      • 1970-01-01
      • 2019-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-21
      • 2021-07-26
      • 2019-12-10
      • 1970-01-01
      相关资源
      最近更新 更多