Home > OS >  Provide an InjectionToken after APP_INITIALIZATION with the resolved configuration
Provide an InjectionToken after APP_INITIALIZATION with the resolved configuration

Time:09-23

I need to get the config using a factory that will be resolved during the APP INITIALIZATION (using the APP_INITIALIZER provider).

export function loadConfig(): () => Promise<Config> {
    // return promised config
}

That is provided using the AppModule:

providers: [{
  provide: APP_INITIALIZER,
  useFactory: loadConfig,
  deps: [HttpClient, ConfigService],
  multi: true
}]

Then I need to use that configuration data in inject something inside another InjectionToken, but if I provide the specific injectiontoken using the config provided during the app initialization, that process is executed before the APP_INITIALIZER execution.

export const FORMATS = new InjectionToken<Formats>("formats")

export assignFormat(configService: ConfigService) {
    return configService.getFormats(); // Needs to execute after APP_INITIALIZER, not before
}
providers: [{
  provide: APP_INITIALIZER,
  useFactory: loadConfig,
  deps: [HttpClient, ConfigService],
  multi: true
}, {
  provide: FORMATS,
  useFactory: assignFormat,
  deps: [ConfigService]
}]
@Injectable({ providedIn: "root" })
export class ConfigService {
    constructor() {}
    getFormats() {}
}

How can I do to provide the injection token after the APP initialization?

CodePudding user response:

What you have here should actually work, if your loadConfig factory returns a function instead of the actual promise:

const loadConfig = (configService: ConfigService) => {
  return () =>
    new Promise<void>((resolve, reject) => {
      // I added the timeout to simulate a delay
      setTimeout(() => {
        // you might be using a http call to get the config from the server instead.
        // Make sure you keep the config that you fetched in the service;
        // this way you can inject the service in the next factory function 
        // and have the config available
        configService.config = {
          formats: 'formats',
        };
        resolve();
      }, 1000);
    });
};

The provision of the APP_INITIALIZER looks exactly like in your code:

{
  provide: APP_INITIALIZER,
  useFactory: loadConfig,
  deps: [ConfigService],
  multi: true,
},

When you set up the next injection token, you should have the config available to use

{
  provide: FORMATS,
  useFactory: (configService: ConfigService) => {
    // getFormats method must not be async, it needs to return the actual 
    // formats that were fetched during the app initialization phase
    return configService.getFormats();
  },
  deps: [ConfigService],
},

The only async factories that are allowed in Angular are the ones you use with the APP_INITIALIZER injection token, but beware that from these, you need to return a function instead of the actual value.

  • Related