App.Settings - the Angular Way

App.settings - the Angular way?

I figured out how to do this with InjectionTokens (see example below), and if your project was built using the Angular CLI you can use the environment files found in /environments for static application wide settings like an API endpoint, but depending on your project's requirements you will most likely end up using both since environment files are just object literals, while an injectable configuration using InjectionToken's can use the environment variables and since it's a class can have logic applied to configure it based on other factors in the application, such as initial HTTP request data, subdomain, etc.

Injection Tokens Example

/app/app-config.module.ts

import { NgModule, InjectionToken } from '@angular/core';
import { environment } from '../environments/environment';

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');

export class AppConfig {
apiEndpoint: string;
}

export const APP_DI_CONFIG: AppConfig = {
apiEndpoint: environment.apiEndpoint
};

@NgModule({
providers: [{
provide: APP_CONFIG,
useValue: APP_DI_CONFIG
}]
})
export class AppConfigModule { }

/app/app.module.ts

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

import { AppConfigModule } from './app-config.module';

@NgModule({
declarations: [
// ...
],
imports: [
// ...
AppConfigModule
],
bootstrap: [AppComponent]
})
export class AppModule { }

Now you can just DI it into any component, service, etc:

/app/core/auth.service.ts

import { Injectable, Inject } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

import { APP_CONFIG, AppConfig } from '../app-config.module';
import { AuthHttp } from 'angular2-jwt';

@Injectable()
export class AuthService {

constructor(
private http: Http,
private router: Router,
private authHttp: AuthHttp,
@Inject(APP_CONFIG) private config: AppConfig
) { }

/**
* Logs a user into the application.
* @param payload
*/
public login(payload: { username: string, password: string }) {
return this.http
.post(`${this.config.apiEndpoint}/login`, payload)
.map((response: Response) => {
const token = response.json().token;
sessionStorage.setItem('token', token); // TODO: can this be done else where? interceptor
return this.handleResponse(response); // TODO: unset token shouldn't return the token to login
})
.catch(this.handleError);
}

// ...
}

You can then also type check the config using the exported AppConfig.

appsettings.json file loading after app init on APP_INITIALIZER

So everything was well configured except from one important thing: Constructors are used only to inject dependencies. So at that point, I cannot make this:

constructor(private readonly httpClient: HttpClient,
private configService: ConfigService) {
this.apiUrl = this.configService.apiBaseUrl;
}

SOLUTION

I removed then the line inside the constructor:

constructor(private readonly httpClient: HttpClient,
private configService: ConfigService) {
}

And just called the apiBaseUrl wherever I needed it and it worked:

public get<T>(url: string): Observable<T> {
return this.httpClient.get<T>(`${this.configService.apiBaseUrl}${url}`);
}

Trying to set environment variables in appSettings.json - Angular and Typescript

As stated in comment, appsettings.json is not for angular application. here you can go through this tutorial to find necessary steps for using enviornment.
here are some quick steps:

import { environment } from './../environments/environment';
...
const baseUrl: string = environment.baseUrl;

where environment.ts may look like

export const environment = {
production: false,
baseUrl: "http://localhost:45644/api/",
};

live example here

How do I create an app specific configuration for Angular with NX/Nrwl?

From what I can understand, IMHO, you should keep DefaultAppConfig in shared/config and CarAppConfig in app-car.

Reason: As the name suggest, shared is shared by all libs. So, why should other app have access to an object which is out of its scope.

You can extend DefaultAppConfig in all apps and use it in its app-car.module or something.

Side note: You can also explore the concept of Tags to have more control over what can be imported into a lib and what should not.

Please let me know if I get it correctly.



Related Topics



Leave a reply



Submit