0

In my angular app, I want to use runtime configuration (to use same build artifact for any target env) and load settings from the back .net API. I have the following api url in the config.json in the assets folder.

{
  "apiUrl": "https://localhost:xxx"
}

and the configuration service that will call the back end api to get all the evnironment settings looks like below

export class ConfigService {
config: Config;
private configEndPoint = '/config';
private environmentSettings: EnvironmentSettings; 

constructor(private http: HttpClient) { }

loadConfig(): Observable<EnvironmentSettings> {
  return this.http
  .get<Config>('./assets/config.json')
  .pipe(
    switchMap(config => {
      return this.http.get<EnvironmentSettings>(config.apiUrl + this.configEndPoint)
    }))

  }

 getEnvironmentSettings(){
   return this.environmentSettings;
 }

}

In the app module I have createf factory function for app intialiser like below

export const configFactory = (configService: ConfigService) => {
  return () => configService.loadConfig();
 };

and the providers array includes

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

The problem I have is I'm not able to set the value for enviornement settings in the load config. The loadConfig method is called by the factory function and call is made to the back end api. In the angular app, I want to inject ConfigService in components and call the getEnvironmentSettings of ConfigService to get all the settings but not sure how this can be set in the above scenario?

rumi
  • 3,293
  • 12
  • 68
  • 109
  • I'm not sure whether I understand your question correctly, but in order to retrieve a value by the `getEnvironmentSettings()` method, you just have to add another line to your `pipe` chain: `tap((x) => (this.environmentSettings = x))`. Afterwards injecting `ConfigService` and calling the method will return the previously loaded value. – Eddi May 15 '23 at 12:07
  • How can we use tap before returning the observable? – rumi May 15 '23 at 12:31
  • What do you mean exactly by that? The `tap` RxJs operator will run the method (in this case setting the `environmentSettings` property) as soon as the value is available. Did you try to add it and encountered a problem? – Eddi May 15 '23 at 13:26
  • I'm returning a new observable with the switchmap. Not sure how can we use tap op to set the configuration value before returning the observeable. Its the config that's coming back from the rest api in the 2nd http call in the code above – rumi May 15 '23 at 13:28

1 Answers1

1

In order to make the value of environmentSettings available, you have to set the value of it with the RxJS tap operator. With the tap operator you can create side-effects for observables.

In your case the side-effect will be setting the environmentSettings variable.

export class ConfigService {
config: Config;
private configEndPoint = '/config';
private environmentSettings: EnvironmentSettings; 

constructor(private http: HttpClient) { }

loadConfig(): Observable<EnvironmentSettings> {
  return this.http
  .get<Config>('./assets/config.json')
  .pipe(
    switchMap(config => {
      return this.http.get<EnvironmentSettings>(config.apiUrl + 
     this.configEndPoint)
    }),
    //variable 'settingsFromEndpoint' will contain the value from the http request
    tap((settingsFromEndpoint) => (this.environmentSettings = settingsFromEndpoint))
   )
  }

 getEnvironmentSettings(){
   return this.environmentSettings;
 }

With this setup your configFactory will be called, which will instantiate your ConfigService and call the method loadConfig. Since the return type of that method is an observable Angular will wait for the observable to emit its first value. As soon as the first value is emitted the callback of the tap operator is called and your variable environmentSettings will be set to the result of the endpoint.

Eddi
  • 782
  • 1
  • 7
  • 20