Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load config.json and use the configuration values in another module?

I'm trying to move all configuration values from environment.ts to config.json, so I can use the same build for multiple different environments (development, staging and production).

I have been following the suggestion written in here, VSTS build - replace Angular4 environment variables in Release stage but in my case, I'm using some of the configuration values in another module, namely core.module which I'm setting up Azure MSAL details like Client Id, redirect Uri, etc.

I'm hitting an error saying that the configuration values that I need for setting up Azure MSAL are not yet loaded up.

config.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Config } from 'src/app/model/config';

export let CONFIG: Config;

@Injectable()
export class ConfigService {

  constructor(private http: HttpClient) { }

  public load() {
    return new Promise((resolve, reject) => {
      this.http.get('/assets/config/config.json')
        .subscribe((envResponse: any) => {
          const t = new Config();
          CONFIG  = Object.assign(t, envResponse);
          resolve(true);
        });

    });
  }
}

export function configFactoryService(configService: ConfigService): Function {
  return () => configService.load();
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { LOCALE_ID, NgModule, APP_INITIALIZER } from '@angular/core';

// Load the required calendar data for the de locale
import '@progress/kendo-angular-intl/locales/en-DK/all';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { routingModule } from './app.routing';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { HomeModule } from './modules/home/home.module';
import { ConfigService, configFactoryService } from './core/services/config.service';
import { HttpClient, HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    BrowserAnimationsModule,
    HomeModule,
    SharedModule,
    CoreModule,
    routingModule,
    HttpClientModule
  ],
  providers: [
    ConfigService,
    {
      provide: APP_INITIALIZER,
      useFactory: configFactoryService,
      deps: [
        ConfigService,
        HttpClient
      ],
      multi: true
    },
    { provide: LOCALE_ID, useValue: 'en-DK' }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

core.module.ts

import { NgModule } from '@angular/core';
import { NavigationComponent } from './components/navigation/navigation.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { AuthMSALCustomInterceptor } from './interceptors/auth.msal.custom.interceptor';
import { MsalModule } from '@azure/msal-angular';
import { CONFIG as environment } from './services/config.service';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule,
    HttpModule,
    MsalModule.forRoot({
      clientID: environment.clientID,
      authority: environment.authority,
      validateAuthority: true,
      redirectUri: environment.redirectUri,
      popUp: false,
      consentScopes: [
        `api://${environment.sApplicationId}/access_as_user`,
        `api://${environment.wApplicationId}/access_as_user`,
        `api://${environment.oApplicationId}/access_as_user`,
      ],
      protectedResourceMap: [
        [
          environment.sUrl,
          [`api://${environment.sApplicationId}/access_as_user`]
        ],
        [
          environment.wUrl,
          [`api://${environment.wApplicationId}/access_as_user`]
        ],
        [
          environment.oUrl,
          [`api://${environment.oApplicationId}/access_as_user`]
        ]
      ]
    })
  ],
  exports: [
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    NavigationComponent
  ],
  declarations: [NavigationComponent],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthMSALCustomInterceptor,
      multi: true
    }
  ],
})
export class CoreModule { }

I need to be able to load the configuration values and use them in core.module. Is there a way to load config.json values even before the modules are initialized?

EDIT: A screenshot to show where the error occurs - core.module error

like image 478
Helmi Khaled Avatar asked Nov 06 '22 14:11

Helmi Khaled


1 Answers

After a good amount of digging including the original blog post in this link, I landed on an implementation in the comments (https://link.medium.com/QleSbGcCb7) that I liked the most, it's relatively simple and easy to follow. Hope this helps. See the link for full implementation, but here's the gist. Note that you'll need a config file and a model for you config.

fetch('./config.json')
  .then((response) => response.json())
  .then((config: ShellModuleConfig) => {
     if (environment.production) {
        enableProdMode();
     }

    platformBrowserDynamic(
      [{ provide: SHELL_RUNTIME_CONFIG, useValue: config }]
    )
    .bootstrapModule(AppModule)
    .catch((err) => console.error(err));
  });
like image 169
patrickbadley Avatar answered Nov 14 '22 22:11

patrickbadley