Angular2 DI: How to inject dependency under @NgModule?
Asked Answered
A

0

7

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 ?

  1. ExternalModule.forRoot(@Inject(MyConfig) config : MyConfig)
  2. 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:

  1. Use of an exported OpaqueToken from the third party provider side like here (Angular 2 Router)
  2. 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?

Armandinaarmando answered 18/10, 2016 at 11:13 Comment(1)
You can't inject into decorators. Perhaps you are looking for #37612049Ornamented

© 2022 - 2024 — McMap. All rights reserved.