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.
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.
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],
}),
I have a problem with dynamically injecting providers from forRoot
section into ModuleWithProviders
from CoreInterceptorModule .
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 },
],
};
}
}
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;
}
}
This piece of code causing an exception:
ERROR in Error during template compile of 'AppModule' Function calls are not supported in decorators but 'CoreInterceptorModule' was called.
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.
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).
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[];
}
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']
},
]),
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
],
};
}
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.