2

I am writing a library service for Angular 2 and I wish for the calling application to be able to supply some configuration. I could make abstract properties on the base classes, but this would lead to a lot the calling application having to define the configuration in multiple places.

Within Angular2 applications I use a technique like this in the main application module

let config: any = { param1: 'value 1', param2: 'value 2' };

@NgModule({
    providers: [ {provide: 'app.config', useValue: config } ]
})

I can then inject the config where needed with @Inject('app.config') . However, as the library I am writing is defining base classes to be extended I don't want to have this value injected on the constructor as it would require the calling application to inject the value and forward it via super().

I've been looking at the ReflectiveInjector class, but it wants a type rather than a string.

    let appConfig = ReflectiveInjector.resolve('app.config').get();

How can I achieve this?

ciantrius
  • 683
  • 1
  • 6
  • 21

2 Answers2

0

I've been looking at the ReflectiveInjector class, but it wants a type rather than a string.

Something like this?

let config: any = { param1: 'value 1', param2: 'value 2' };

let injector: any = ReflectiveInjector.resolveAndCreate([
  {
    provide: 'app.config',
    useValue: config
  }
]);

let configService = injector.get('app.config');

console.log(configService);
Michael
  • 1,692
  • 1
  • 17
  • 19
  • This wouldn't work for me as my code is a library, so wouldn't be able to share the injector variable with the host application – ciantrius Nov 11 '16 at 14:44
0

You can define an OpaqueToken

export const APP_CONFIG = new OpaqueToken('app.config');

And use it as a type, instead of using a string

let appConfig = ReflectiveInjector.resolve(APP_CONFIG).get();

If I understood correctly, you want to load some configuration data with a single request before the application initializes, and keep it in a singleton. I strongly recommend you having a look at the post #37611549, as it explains use of APP_INITIALIZER - to execute a function when the app is initialized and delay what it provides if the function returns a promise.

Community
  • 1
  • 1
Burak Tasci
  • 887
  • 12
  • 18
  • Your understanding is almost correct. I would like the application using my library to load some configuration and make it available to me globally. If I try the OpaqueToken I get the following build error "TS2345: Argument of typ e 'OpaqueToken' is not assignable to parameter of type 'Provider[]'. Property '[Symbol.iterator]' is missing in type 'OpaqueToken'." – ciantrius Nov 11 '16 at 12:56
  • did you import the OpaqueToken using – Burak Tasci Nov 11 '16 at 13:23
  • `import { OpaqueToken } from '@angular/core';` – Burak Tasci Nov 11 '16 at 13:23
  • Yes. One of the few benefits of WebStorm – ciantrius Nov 11 '16 at 14:37
  • Yes. Interestingly, with const token: OpaqueToken = new OpaqueToken('app.config'); I get the error above, but if I change to const token: any I get a different error. "error TS2339: Property 'get' does not exist on type 'ResolvedReflectiveProvider[]'." – ciantrius Nov 11 '16 at 14:43
  • now i get it! it seems that the injector is expecting a type.. first, create an interface called "AppConfig" with relevant properties, and then try injecting the APP_CONFIG token as a type of "AppConfig".. app.config.ts `export const APP_CONFIG = new OpaqueToken('app.config'); export interface AppConfig { prop1: string; prop2: string; }` dummy.component.ts `constructor(@Inject(APP_CONFIG) private appConfig: AppConfig) {}` – Burak Tasci Nov 11 '16 at 16:07