在加载我的angular 2应用之前,我试图从数据库中获取一些配置选项。角度应用程序需要在启动之前等待加载的数据,因为应该根据这些配置选项限制对某些组件的访问。
所以我创建了一个ConfigurationService来从后端获取数据,我试图在启动应用程序之前使用root模块中的app_initializer来调用配置服务。我已经设法在几个月前创建的一个有角度的应用程序(角度RC4)中做到了这一点,并且这次尝试以同样的方式进行此操作。
app.module.ts - 首先尝试
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 { }
这导致以下错误:
Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function
我认为这与AoT编译器有关,我正在使用它。我用工厂替换了lambda表达式。
app.module.ts - 第二次尝试
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;
}
);
}
这实际上是使用配置服务从后端获取数据,但在启动应用程序之前不等待承诺解析。当用户在主页(可供所有人访问)启动时,它可以工作,然后导航到受非管理员用户限制的组件。但是当用户刷新受限制的页面时,OnInit(我确定用户是否具有访问权限)会在加载配置之前触发。在我的情况下,导致用户被拒绝访问他们应该访问的页面。
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);
}
}
组件实施
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");
}
}
}
我现在所有的想法都没有,我找了一个解决方案,但只是设法找到推荐lambda选项的人,这对我不起作用。
答案 0 :(得分:5)
在angular gitter channel的@DzmitryShylovich的帮助下,他指出从app.module.ts内部调用服务是为了迟到,我应该从main.ts文件中调用该服务,我设法解决了我的问题。他向我提供了以下plnkr。
这就是我在自己的解决方案中所做的工作。
<强> constants.ts 强>
import { OpaqueToken } from '@angular/core'
export const CONFIG_TOKEN = new OpaqueToken('config');
我创建了一个OpaqueToken to avoid naming collisions
<强> main.ts 强>
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
import { CONFIG_TOKEN } from './shared/constants/constants'
const configApi = "yoururlhere";
fetch(configApi, {
credentials: 'include'
}).then(parseResponse);
function parseResponse(res: any) {
return res.json().then(parseData);
}
function parseData(data: any) {
return platformBrowser([{ provide: CONFIG_TOKEN, useValue: data }]).bootstrapModuleFactory(AppModuleNgFactory);
}
在我的main.ts文件中,我调用webservice来获取配置数据,解析数据并创建一个提供程序以传递到我的应用程序中。我设置了要包含的凭据,因为我在webservice上使用了Windows身份验证,当你没有明确地告诉fetch提供凭据时,它会给出401。
<强> app.component.ts 强>
import { Component, OnInit, Inject } from "@angular/core";
import { CONFIG_TOKEN } from './shared/constants/constants'
@Component({
selector: "app",
templateUrl: "app.component.html"
})
export class AppComponent implements OnInit {
public configuration: any;
public isAdmin: boolean;
constructor(@Inject(CONFIG_TOKEN) config: any) {
this.configuration = config;
}
ngOnInit() {
this.isAdmin = this.configuration.currentUser_IsAdmin;
}
}
在我的app.component中,我可以注入我创建的提供程序,以使用我从webservice获得的配置对象。
打字稿问题
在开发此解决方案时,我遇到了visual studio中的打字稿问题,我收到以下错误:
error TS2304: Cannot find name 'fetch'.
我通过手动下载whatwg-fetch typescript定义文件
解决了这个问题npm install --save-dev @types/whatwg-fetch
@DzmitryShylovich,谢谢你的帮助!