I'm trying to get some configuration options from the database before loading my angular 2 app. The angular app needs to wait for the data being loaded before starting because access to certain components should be restricted based on these configuration options.
So I've created a ConfigurationService to get the data from the backend and I'm trying to use the app_initializer in the root module to call the configurationservice before starting the app. I've managed to do this in an angular app I've created a few months ago (angular RC4) and tried to do It the same way this time around at first.
app.module.ts - First try
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { ConfigurationService } from "./shared/services/configuration.service";
@NgModule({
imports: [
...
],
declarations: [
...
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: (config: ConfigurationService) => () => config.loadConfiguration(),
deps: [ConfigurationService]
},
ConfigurationService
],
bootstrap: [AppComponent]
})
export class AppModule { }
This resulted in the following error:
Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function
I think this has something to do with the AoT compiler, which I'm using. I've replaced the lambda expressions with a factory.
app.module.ts - Second try
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { ConfigurationService } from "./shared/services/configuration.service";
import { ConfigurationServiceFactory } from "./shared/services/configuration.service.factory";
@NgModule({
imports: [
...
],
declarations: [
...
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: ConfigurationServiceFactory,
deps: [ConfigurationService]
},
ConfigurationService
],
bootstrap: [AppComponent]
})
export class AppModule { }
configuration.service.factory.ts
import { ConfigurationService } from "./configuration.service";
export function ConfigurationServiceFactory(configurationService: ConfigurationService) {
return configurationService.loadConfiguration()
.then(currentUser => {
configurationService.currentUser = currentUser;
}
);
}
This actually gets the data from the backend using the configurationservice, but doesn't wait for the promise to resolve before starting the app. It works when the user starts at the homepage (which is accessible for everyone) and then navigates to a component which is restricted for non admin users. But when the user refreshes the page which is restricted, the OnInit (where I determine if a user has access) fires before the configuration can be loaded. Which, in my case, results in users to be denied access to pages they should have access to.
configuration.service.ts
import { Injectable } from "@angular/core";
import { Http, Response } from '@angular/http';
import { CurrentUser } from "../models/currentuser.model";
@Injectable()
export class ConfigurationService {
public apiUrl: string = "api/";
public currentUser: CurrentUser;
constructor(private http:Http) {}
/**
* Get configuration from database
*/
public loadConfiguration(): Promise<CurrentUser> {
return this.http.get(this.apiUrl + "application/GetDataForCurrentUser")
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
}
Component implementation
import { Component, OnInit } from '@angular/core';
import { MessageService } from '../shared/message/message.service'
import { ConfigurationService } from "../shared/services/configuration.service";
@Component({
selector: 'simple',
templateUrl: 'simple.component.html'
})
export class SimpleComponent implements OnInit{
constructor(private messageService: MessageService, private configurationService: ConfigurationService) {
}
ngOnInit() {
if (!this.configurationService.isAdmin()) {
this.messageService.addMessage("Access denied", "danger");
}
}
}
I'm all out of ideas at this time, I've looked for a solution but only managed to find people recommending the lambda option, which is not working for me.