本文介绍了具有forRoot的动态提供程序数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writting an angular2 InterceptorModule which is part of big core project. Every module needs to be fully configurable and independent. All modules are written with foorRoot method wchich allow us to achieve global singletons and pass any configuration into it.

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

We decided to define HTTP_INTERCEPTORS providers in forRoot metod of main module. Thanks to this we have one configuration in one place with all URL rules to fire particular interceptors.

这是主要 AppModule import 部分中的简单用法:

This is simple usage in import section of main AppModule:

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 部分中的提供程序动态注入到 CoreInterceptorModule ModuleWithProviders 中时遇到问题.

I have a problem with dynamically injecting providers from forRoot section into ModuleWithProviders from CoreInterceptorModule.

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

This is a working solution of injecting 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 的数量是动态的.

Of course this solution is bad because amount of HTTP_INTERCEPTORS defined in forRoot is dynamic.

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

Solution is just to inject providers dynamically, like that:

@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 语句之前调用任何函数.

I read some topics about this problem and none of them helped in my case. The problem is that it's not possible to call any function before return statement in forRoot method.

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

The question is how dynamically add HTTP_INTERCEPTORS in forRoot method? I thought about something like useFactory but it seams it can return just one value (one instance).

推荐答案

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

I resolved this problem. Instead of using my custom configuration type IInterceptorConfig (which is later impossible to iterate) I created custom Angular DI provider type inherited from original Angular\@code\classProvider:

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

感谢此我还有其他字段. forRoot 方法配置如下:

Thanks to this I have my additional fields. forRoot method configuration looks like that:

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

最后,最重要的一点是,我可以动态地在sharedModule中填充 ModuleWithProviders 接口:

And finally and the most important I can dynamically fill ModuleWithProviders interface in sharedModule without errors:

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

它之所以有效,是因为我使用了数组扩展运算符( ... )而不是任何其他函数调用.此解决方案的唯一弊端是一些不必要的属性,例如 provide useClass multi ,这些属性不能封装在任何较低的层中.

It works because I use array spread operator (...) instead of any additional functions call. The only cons of this solution is some unnecessary attributes like provide, useClass, multi which can not be encapsulated in any lower layer.

这篇关于具有forRoot的动态提供程序数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-30 02:01