In my Angular2 app, I'm trying to load configurations from backend on bootstrap using HTTP so that I can use the extracted data for creating angular services.
Whenever I try to read the HTTP response saved in my Config, I always get TypeError: Cannot read property 'url' of undefined error.
It appears like the HTTP request completes only when the whole bootstrap method finishes, whereas my code tries to extract the Observable response before it is retrieved.
How can I fix it to extract configuration from server and use it to create angular services on startup? (I want to create services inside providers with extracted data)
Please comment if there is any better way of extracting configuration from server on startup.
My main.ts looks like this:
bootstrap(AppComponent,
[APP_ROUTER_PROVIDERS, HTTP_PROVIDERS, ConfigurationService, Config])
.catch(err => console.error(err)
);
configuration.service.ts
@Injectable()
export class ConfigurationService {
constructor(private http: Http) {
}
load() {
return this.http.get('config/getConfig').map(response => response.json());
}
}
config.ts
@Injectable()
export class Config {
public config;
constructor(public configurationService: ConfigurationService) {
configurationService.load().subscribe(
config => this.config = config,
error => console.error('Error: ' + error)
);
}
get(key: any) {
return this.config[key];
}
}
app.component.ts
@Component({
selector: 'app',
templateUrl: 'app/app.component.html',
styleUrls: ['app/app.component.css'],
directives: [ROUTER_DIRECTIVES],
providers: [MyService]
})
export class AppComponent {
constructor(public myService: MyService) {
}
}
my.service.ts
@Injectable()
export class MyService{
private url;
constructor(public config: Config) {
this.url = config.get('url');
}
}
You could leverage the APP_INITIALIZER
service to reload the configuration before application starts:
bootstrap(AppComponent, [
{
provide: APP_INITIALIZER,
useFactory: (config:Config) => {
return config.load();
},
dependency: [ Config ]
}
]);
For this, you need to adapt a bit your ConfigService
class:
@Injectable()
export class ConfigService {
constructor(private http:Http) {}
load() { // <------
return new Promise((resolve) => {
this.http.get(...).map(res=>res.json())
.subscribe(config => {
this.config = config;
resolve();
});
}
}
Then you'll be able to access directly properties on the configuration object within your application.