Samy Sammour
Samy Sammour

Reputation: 2465

Inject API_BASE_URL from angular 7 config

I am working on an Angular 7 Application with es6 Javascript version and Swagger.

I am trying to add the config to APP_INITIALIZER in the app.module:

export class SettingsProvider {
  private config: AppConfig;
  constructor(private httpClient: HttpClient) {}

  public loadConfig(): Promise<any> {
        return this.httpClient.get(`assets/configs/config.json`).pipe(
          map(res => res as AppConfig))
          .toPromise()
          .then(settings => {
            this.config = settings;
          });
      }

   public get configuration(): AppConfig {
     return this.config;
   }
 }

in the app.module:

{ provide: APP_INITIALIZER, useFactory: init, deps: [SettingsProvider], multi: true },
{ provide: API_BASE_URL, useFactory: baseApiUrlSetting, deps: [SettingsProvider], multi: true },

export function init(settingsProvider: SettingsProvider) {
  return () => settingsProvider.loadConfig();
}

export function baseApiUrlSetting(settingsProvider: SettingsProvider) {
  return settingsProvider.configuration.baseApiUrl;
}

Everything works perfectly until I inject the API_BASE_URL token. The compiler is probably not finished with loading the configs so, the value of settingsProvider is always null.

Cannot read property 'baseApiUrl' of undefined

Does anybody know a possible solution for that? Thanks!

Upvotes: 3

Views: 1710

Answers (1)

kwestground
kwestground

Reputation: 48

I had the same problem and ended up with this solution:

main.ts

    AppConfigService.loadConfig().then(() => {
      return platformBrowserDynamic().bootstrapModule(AppModule);
    })

app-config-service.ts

import { Injectable } from '@angular/core';
import { AppConfig } from './app-config.models';

@Injectable({ providedIn: 'root' })
export class AppConfigService<T extends AppConfig = AppConfig> {
  static appConfig: AppConfig;

  constructor() { }

  static loadConfig(): Promise<void> {
    return new Promise((resolve, reject) => {
      const oReq = new XMLHttpRequest();
      oReq.addEventListener('load', (resp) => {
        if (oReq.status === 200) {
          try {
            AppConfigService.appConfig = JSON.parse(oReq.responseText);
          } catch (e) {
            reject(e);
          }
          resolve();
        } else {
          reject(oReq.statusText);
        }
      });
      oReq.open('GET', '/assets/configs/config.json');
      oReq.send();
    });
  }

  getConfig(): T {
    return AppConfigService.appConfig as T;
  }
}

app-config.models.ts

export interface AppConfig {
    ApiBaseUrl: string;
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { API_BASE_URL } from './nswag-client.service';
import { AppConfigService } from '../app-config-service';

export function getApiBaseUrl(): string {
  return AppConfigService.appConfig.ApiBaseUrl;
}

@NgModule({
  declarations: [
    AppComponent,
    ...
  ],
  imports: [
    ...
  ],
  providers:
    [
      {
        provide: API_BASE_URL,
        useFactory: getApiBaseUrl
      },
      ...
    ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Cred to michael-lang https://github.com/ngrx/platform/issues/931

Upvotes: 1

Related Questions