TL;DR 25.10.16: update
I renamed the title to provide more clarification as i am still concerned about the right solution.
Given a module
@NgModule({
imports: [
ExternalModule.forRoot(config),
],
providers: [EXTERNAL_PROVIDERS(config)],
})
export class MyModule{}
So my questions are: is there any possibilty that i can inject a dependency with my passed config like this ?
ExternalModule.forRoot(@Inject(MyConfig) config : MyConfig)
providers: [EXTERNAL_PROVIDERS(@Inject(MyConfig) config)]
(
I do not want to create {provide: xxx, deps :[xxx], useFactory : xxx}
for each given external provider.
I tried to initialize a Application Wide Service Locator
with access to the root injector as described here , but with Angular 2.1.0 ngDoBootstrap
does not work as expected.
----------
Old Post:
I would like to know what the correct pattern is for configuring an external third party library provider in Angular2.
Let's take an example (code samples in Typescript):
There is a library that exposes its providers and offers some configuration options by config
object literal:
export function THIRD_PARTY_PROVIDERS(config = {}): Provider[] {
return [
{
provide: ExtConfigurableService,
deps: [Http],
useFactory: (http: Http) => {
return new ExtConfigurableService(http, config);
}
},
ExtOtherService
];
}
Then on the client side, these providers can be included in an @NgModule
:
@NgModule({
providers: [
THIRD_PARTY_PROVIDERS({foo : 'bar'})
],
})
export class ClientModule { }
But what if my configuration object itself has dependencies on an existent service like MyService
?
I cannot inject a dependency in the providers array. The only way from my point of view is to use a FactoryProvider:
const myConfigProvider = {
provide: MyConfig,
deps: [MyService],
useFactory: (MyService) => {
return new MyConfig(MyService);
}
};
Given that, how can i inject MyConfig
into THIRD_PARTY_PROVIDERS
?
The only solutions which i came up with are not satisfactory:
- Use of an exported
OpaqueToken
from the third party provider side like here (Angular 2 Router) - configure all providers manuallay from the client side
The first can only be done from the third party provider: export the token and require that token as own dependency in the factory provider.
The second is very ugly, because you have to know and configure the implementation details / services of the third party lib by yourself.
@NgModule({
providers: [
{provide: ExtConfigurableService, deps: [MyConfig], useFactory: ...},
ExtOtherService
],
})
export class ClientModule { }
What is the preferred pattern in angular 2 (client and third party provider side)?
Update 19.10.16
I implemented my first proposal for a solution and it works fine. But it requires that you have control over the external library / agree with the project owner on your changes or fork the repo.
third-party-lib.ts:
export const JWT_CONFIGURATION = new OpaqueToken('THIRD_PARTY_PROVIDER_TOKEN');
...
@Injectable()
export class ExtConfigurableService {
constructor(@Inject(JWT_CONFIGURATION) config: any) {
// do someting with client provided config
}
my-module.ts
@NgModule({
providers: [
{
provide: JWT_CONFIGURATION,
deps: [MyService],
useFactory: (mySvc: MyService) => {
return {foo : 'bar'};
}, THIRD_PARTY_PROVIDERS
]
})
export class MyModule { }
But if the external lib requires you to pass your config as an argument (like in the example at the top), i still don't know how to inject myconfig into it.
Has Angular 2 other ways to inject a dependency with @Inject()
in addition to the constructor or the factory provider?