16

I am working with Angular2 RC5. I would like to be able to load my server IP address and some other configuration parameters before my app boots up. How can I do this in the latest RC5?

I have seen other articles, but they are not helpful:

  1. How to preload a config file in angular2: The answer provided here is specific to webpack. I am using systemjs.
  2. https://medium.com/@hasan.hameed/reading-configuration-files-in-angular-2-9d18b7a6aa4#.m8lontnas: This is for the older version of Angular2. Some of the classes used are deprecated.

Any help would be greatly appreciated.

Edit

I tried to use the APP_INITIALIZER as follows in my app.module.ts:

 import { NgModule, provide, APP_INITIALIZER } from "@angular/core"; import { ConfigService } from "./shared/services/config.service"; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, routes, FormsModule, HttpModule], providers: [AuthService, Title, appRoutingProviders, ConfigService], bootstrap: [AppComponent , provide(APP_INITIALIZER, { useFactory: (config: ConfigService) => () => config.load(), deps: [ConfigService], multi: true })] }) export class AppModule { } 

This is my config.service.ts file:

 import { Config } from "../model/config"; export class ConfigService { constructor() { } load(): Promise<Config> { let config: Config = new Config("localhost", "5050"); return Promise.resolve(config); } } 

Note that I will eventually re-write load to actually read a property or some such file to load configuration.

This is what config.ts looks like:

export class Config { constructor( private machine: string, private port: string ) { } private base_url: string = "http://" + this.machine + this.port + "/"; public loginURL: string = this.base_url + "login"; } 

I am getting a compile error

public/app/app.module.ts(27,11): error TS2345: Argument of type '{ declarations: (typeof AppComponent ...' is not assignable to parameter of type 'NgModuleMetadataType'. Types of property 'bootstrap' are incompatible. Type '(typeof AppComponent | Provider)[]' is not assignable to type '(Type | any[])[]'. Type 'typeof AppComponent | Provider' is not assignable to type 'Type | any[]'. Type 'Provider' is not assignable to type 'Type | any[]'. Type 'Provider' is not assignable to type 'any[]'. Property '[Symbol.iterator]' is missing in type 'Provider'. 

Edit 2

I move on to the next step. Update ConfigService to read a json file using http.get. Now I get an error. Here are the updated files:

export class ConfigService { private config: Config; constructor(private http: Http) { } load(): Promise<Config> { this.http.get("/blah/config.json") .map(res => res.json()) .subscribe((env_data) => { console.log(env_data); }); this.config = new Config("localhost", "5050"); return Promise.resolve(this.config); } getConfig(): Config { return this.config; } } 

Here is the providers section in NgModule class

 providers: [AuthService, Title, appRoutingProviders, ConfigService, { provide: APP_INITIALIZER, useFactory: (config: ConfigService) => () => config.load(), deps: [ConfigService, Http], multi: true }], 

Note that in RC6 I am not able to import HTTP_PROVIDERS since I get the error that these are not defined in the http module anymore. This is why I tried Http.

On runtime, I get following error

(index):27 Error: Error: Can't resolve all parameters for ConfigService: (?).(…)(anonymous function) @ (index):27 ZoneDelegate.invoke @ zone.js:332 Zone.run @ zone.js:225(anonymous function) @ zone.js:591 ZoneDelegate.invokeTask @ zone.js:365 Zone.runTask @ zone.js:265 drainMicroTaskQueue @ zone.js:497 ZoneTask.invoke @ zone.js:437 
0

1 Answer 1

34

Provide this in your root module

{provide: APP_INITIALIZER, useValue: () => promise, multi: true}]} 

where () => promise is some call that returns a Promise that resolves to the desired value.

See also How to pass parameters rendered from backend to angular2 bootstrap method

You can pass a service as dependency where you can store the result.

update

export function loadConfig(config: ConfigService) => () => config.load() @NgModule({ declarations: [AppComponent], imports: [BrowserModule, routes, FormsModule, HttpModule], providers: [AuthService, Title, appRoutingProviders, ConfigService, { provide: APP_INITIALIZER, useFactory: loadConfig, deps: [ConfigService], multi: true } ], bootstrap: [AppComponent] }) export class AppModule { } 

update 2

Plunker example

Sign up to request clarification or add additional context in comments.

30 Comments

Hello. I have provided ConfigService as you suggest in my root NgModule but when I debug in the browser config.load() it always returns undefinded.
When using AOT, useFactory should not get a dynamic function, but rather exported function. See stackoverflow.com/a/41636880/499839
@Mika thanks for the hint! AoT wasn't really a thing back then when I posted the answer. Updated my answer.
The problem is that promise inside config.load() method is resolved only after initialization. Do you have any idea how to manage this?
So you mean return () => { return startupService.load() }; yep?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.