【问题标题】:Dynamic providers array with forRoot带有 forRoot 的动态提供程序数组
【发布时间】:2018-04-06 21:26:03
【问题描述】:

我正在编写一个 angular2 InterceptorModule,它是大型核心项目的一部分。每个模块都需要完全可配置和独立。所有模块都使用foorRoot 方法编写,允许我们实现全局单例并将任何配置传递给它。

我们决定在主模块的forRoot 方法中定义HTTP_INTERCEPTORS 提供程序。多亏了这一点,我们在一个地方有了一个配置,其中包含所有 URL 规则来触发特定的拦截器。

这是 AppModuleimport 部分的简单用法:

CoreInterceptorModule.forRoot([
  {
    instance: TestInterceptor,
    runConditions: [],
  },
  {
    instance: MenuInterceptor,
    runConditions: [InterceptorRunConditions.WhiteList],
    whiteList: ['v1/'],
  },
  {
    instance: MenuInterceptor,
    runConditions: [
      InterceptorRunConditions.WhiteList, 
      InterceptorRunConditions.BlackList
    ],
    whiteList: ['v1/'],
    blackList: ['v1/authorize']
  },
]),

CoreStorageModule.forRoot({
  mode: StorageMode.LocalStorage,
  prefix: 'plCore',
  modesPriority: [StorageMode.SessionStorage, StorageMode.Memory],
}),

我在将提供程序从forRoot 部分动态注入到来自CoreInterceptorModuleModuleWithProviders 时遇到问题。

工作场景

这是注入HTTP_INTERCEPTORS的有效解决方案:

@NgModule({})
export class CoreInterceptorModule {
  static config(interceptorConfig: IInterceptorConfig[]): ModuleWithProviders {
    return {
      ngModule: CoreInterceptorModule,
      providers: [
        { provide: INTERCEPTOR_CONFIG, useValue: interceptorConfig },
        { provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[0].instance, multi: true },
        { provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[1].instance, multi: true },
        { provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[2].instance, multi: true },
      ],
    };
  }
}

这个解决方案当然不好,因为在forRoot 中定义的HTTP_INTERCEPTORS 的数量是动态的。

不工作场景

解决方案就是动态注入提供者,像这样:

@NgModule({})
export class CwaCoreInterceptorModule {
  static forRoot(interceptorConfig: IInterceptorConfig[]): ModuleWithProviders {

    // base module configuration
    const moduleWithProviders: ModuleWithProviders = {
      ngModule: CwaCoreInterceptorModule,
      providers: [
        { provide: INTERCEPTOR_CONFIG, useValue: interceptorConfig },
      ],
    };

    // update HTTP_INTERCEPTORS array
    interceptorConfig.forEach((e) => {
      moduleWithProviders.providers.push({
        provide: HTTP_INTERCEPTORS, useClass: e.instance, multi: true
      });
    });

    return moduleWithProviders;
  }
}

这段代码导致异常:

“AppModule”模板编译期间出现错误 装饰器不支持函数调用,但“CoreInterceptorModule” 被调用了。

我阅读了一些关于这个问题的主题,但没有一个对我有帮助。问题是在forRoot方法中,在return语句之前不能调用任何函数。

问题是如何在forRoot方法中动态添加HTTP_INTERCEPTORS?我想过像useFactory 这样的东西,但它似乎只能返回一个值(一个实例)。

【问题讨论】:

  • 我遇到了类似的问题,并决定不在共享模块中而是在核心模块中创建提供程序。只需使用 @Inject 装饰器将它们注入共享模块。
  • @Akanksha 谢谢你的回复。我尝试了useClass 以及其他静态/非静态辅助函数。不工作。 @AlexanderPoshtaruk 如果没有任何解决方案,我将遵循您的建议并将我的概念重组为与您的类似

标签: angular


【解决方案1】:

我解决了这个问题。我没有使用我的自定义配置类型 IInterceptorConfig(后来无法迭代),而是创建了继承自原始 Angular\@code\classProvider 的自定义 Angular DI 提供程序类型:

export interface InterceptorClassProvider extends ClassProvider {
  runConditions: InterceptConditions[];
  whiteList?: string[];
  blackList?: string[];
}

多亏了这个我有了额外的字段forRoot方法配置如下:

CwaCoreInterceptorModule.forRoot([
  {
    provide: HTTP_INTERCEPTORS,
    useClass: MenuInterceptor,
    multi: true,
    runConditions: [InterceptConditions.WhiteList],
    whiteList: ['/v1']
  },
]),

最后也是最重要的,我可以在 sharedModule 中动态填充ModuleWithProviders 接口而不会出错

static forRoot(interceptorProviders: InterceptorClassProvider[]): ModuleWithProviders {
  return {
    ngModule: CwaCoreInterceptorModule,
    providers: [
      { provide: INTERCEPTOR_CONFIG, useValue: interceptorProviders },
      ...interceptorProviders
    ],
  };
}

之所以有效,是因为我使用数组扩展运算符 (...) 而不是任何其他函数调用。此方案的唯一缺点是一些不必要的属性,如provideuseClassmulti,它们不能封装在任何较低层中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 2013-07-21
    • 1970-01-01
    • 2011-09-09
    • 2015-03-24
    • 2012-11-08
    • 2020-02-11
    • 1970-01-01
    相关资源
    最近更新 更多