Dynamic application configuration in Angular

How do you hold API endpoint URLs in your Angular application? How do you hold other things which might be changed at any point in time? What if you have multiple clients for the same application and they all need very specific application configurations? Do you build the application multiple times, once for each client? Or… do you put all of this into a configuration file which gets loaded on application startup? We do the latter.

One of our clients needed to have a JSON file which would hold application configuration and it was our job to ensure this file would be loaded before anything else. The scenario is that some other piece of software could influence this file and therefore influence the behavior of our application. So we delivered.

 

First thing we did is we discussed what this config file should contain. Upon agreeing that it should contain urlA, urlB and urlC, we created a simple file that holds a JSON object like this:

{

"urlA": "http://our-url.net/urlA",

"urlB": "http://some-other-url.net",

"urlC": "http://one-more-url.net/token"

}

 

File was saved under assets/appConfig.json. Next, we needed to make sure that this JSON object can be described easily:

export interface IAppConfig {

urlA: string;

urlB: string;

urlC: string;

}

 

 

Interface was saved under shared/models/app-config-model.ts. All of this would mean nothing if we would not load it properly in the application lifecycle, so we did just that:

import { Injectable } from '@angular/core';

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

import { IAppConfig} from './shared/models/app-config-model';

@Injectable()

export class AppConfig {

static settings: IAppConfig;

constructor(private http: HttpClient) {}

load() {

const jsonFile = `assets/appConfig.json`;

return new Promise<void>((resolve, reject) => {

this.http.get(jsonFile).toPromise().then((response : IAppConfig) => {

AppConfig.settings = <IAppConfig>response;

localStorage.setItem(urlA, AppConfig.settings.urlA);

localStorage.setItem(urlB', AppConfig.settings.urlB);

localStorage.setItem(urlC, AppConfig.settings.urlC);

resolve();

}).catch((response: any) => {

reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);

});

});

}

}

 

We named this file app.config.ts and saved it next to the app.module.ts. Code is pretty self-explanatory, there is a load() function which loads the appConfig.json and saves its contents into settings variable as well as into localStorage of the browser. HttpClient is injected because we load the JSON file via GET method.

 

Now when we know how a file gets loaded, we need to provide this logic to our root module, in this case app.module.ts. We must do the following:

 

  1. Import APP_INITIALIZER and AppConfig

import { NgModule, APP_INITIALIZER } from '@angular/core';

import { AppConfig } from './app.config';

 

  1. Create our initializeAppConfiguration function which executes load() function from config.ts (do this BEFORE @NgModule decorator

export function initializeAppConfiguration(appConfig: AppConfig) {

return () => appConfig.load();

}

 

  1. Provide our AppConfig and initializeApp function to our module

providers: [

AppConfig,

{

provide: APP_INITIALIZER,

useFactory: initializeApp,

deps: [AppConfig], multi: true

},

 

And this is all there is to it. It always works, app.Config.json always gets loaded on application startup and we always have the freshest info from this file whenever a user loads the appliaction.

Share this post

Subscribe to our newsletter

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla.

Thanks for subscribed!

Processing...

Related posts