Is it possible to set an OpaqueToken via an observ

2019-09-14 00:22发布

问题:

This question already has an answer here:

  • How to pass parameters rendered from backend to angular2 bootstrap method 4 answers

I'm trying to set an opaquetoken in the providers using an observable. Reason being is I'm reading the value via the Http provider (external JSON file).

This is what I'm trying to do

    {
        provide: SOME_OPAQUE_TOKEN,
        useFactory: (configService: ConfigService) => {
            configService.getPath('campaigns')
               .subscribe((res) => {
                   ???
               });
        },
        deps: [ConfigService],
    },

So obviously this wont work but I'm wondering if there is a solution for this sort of problem?

Or if its actually possible to construct a service using useFactory where one of your parameters is retrieved asynchronously.

Is it possible at all?

Edit: Solution using APP_INITIALIZER

In AppModule:

{
  provide: APP_INITIALIZER,
  useFactory: (configService: ConfigService) => () => configService.load(),
  multi: true,
  deps: [ConfigService, Http],
},

In ConfigService load():

public load(): Promise<Configuration> {
    let promise =
        this.http
            .get('config.json')
            .map(m => m.json())
            .toPromise();

    promise
        .then(config => this.appConfig = config);

    return promise;
}

Once we set the appConfig we can use it to set the OpaqueToken:

    {
        provide: BASE_PATH,
        useFactory: (configService: ConfigService) => configService.appConfig.basePath, deps: [ConfigService],
    },

回答1:

APP_INITIALIZER undocumented multi-provider is supposed to be used to resolve app dependencies asynchronously.

An initializer is supposed to be a function that returns a promise (for async initialization) or any other value (for sync initialization). Since APP_INITIALIZER is multi-provider, there can be many initializers, they will be executed in parallel and awaited. The implementation is here.

It can be defined as a provider in module:

{
  provide: APP_INITIALIZER,
  useFactory: (...deps...) => () => promise,
  deps: [...deps...],
  multi: true
}

Or for an initializer without dependencies:

{
  provide: APP_INITIALIZER,
  useValue: () => promise,
  multi: true
}