razorsyntax
razorsyntax

Reputation: 359

How to Load Environment Data for app.modules.ts in Angular

I need to load data from a service which contains environment data. I need some of that data for a module in app.modules.

Here's a small app.modules.ts example:

import { CustomEnvironmentService } from './CustomEnvironmentService';

let customService: CustomEnvironmentService;

@NgModule({
    declarations: [...],
    imports: [CustomModule.forRoot(customService.ENVIRONMENT_DATA)],
    providers: [...]
})
export class AppModule {}

First thing to notice is that customService.ENVIRONMENT_DATA is just a public variable in CustomEnvironmentService which gets information from an environment config file called env.js.

The problem is that when the app loads customService.ENVIRONMENT_DATA is undefined. This is understandable as I'm pretty sure the service isn't initialized and hasn't fetched the data.

I found something called APP_INITIALIZER but it appears that I may not be able to use it to read from either that env.js file or will it use my CustomEnvironmentService (which gets the data from env.js).

I'm also basing my implementation on this article: How to use environment variables to configure your Angular application without a rebuild

Any ideas?

Upvotes: 5

Views: 7069

Answers (2)

Aleš Doganoc
Aleš Doganoc

Reputation: 12052

Using the approach from the article you link you cannot use an APP_INITIALIZER because they get called after all the imported modules have initialized what you already discovered.

Since this approach just sets the environment settings as a global window property __env you can just define a global constant in Angular that you assign the value of the environment settings from the window. Then it will be available in all the application. This will be available also immediately when the application starts.

For example you create an environment-data.ts file with the following content:

export const ENVIRONMENT_DATA = window['__env'];

Then just import the constant where you need it and use it.

import { ENVIRONMENT_DATA } from './environment-data';

@NgModule({
    declarations: [...],
    imports: [CustomModule.forRoot(ENVIRONMENT_DATA)],
    providers: [...]
})
export class AppModule {}

Upvotes: 6

tuckerjt07
tuckerjt07

Reputation: 922

I'm not sure on the exact timings as to when it runs but you can read from a file using APP_INITIALIZER.

app.module.ts

export function startupServiceFactory(startupService: StartupService) {
    return () => startupService.load();
}

@NgModule({
    ...
    providers: [
        StartupService,
        {
            provide: APP_INITIALIZER,
            useFactory: startupServiceFactory,
            deps: [StartupService],
            multi: true
        }
    ]
})

startup.service.ts

export class StartupService {
    // I just use private properties on the class to hold the returned values
    private localStartupData: any;

    constructor(private httpClient: HttpClient){}

    load(): any {
        // I'm returning a txt file so I have to set the responseType to text
        this.httpClient.get('<relativePathToFile>/env.js', { responseType: 'text' })
        .pipe(
            catchError((err) => {
                // If I have any defaults in case of file not existing I set them here
                return throwError(err);
            })
        )
        .toPromise()
        .then((data: any) => {
            this.localStartupData = data;
        })
        .catch((err: any) => {
            Promise.resolve();
        });
    }

    get startupData(): any {
        return this.localStartupData;
    }
}

Just make sure that env.js is included in your angular.json

Upvotes: 0

Related Questions