2016-12-08 71 views
4

我試圖加載我的角2的應用程序之前,從數據庫中獲取的一些配置選項。角應用程序需要等待數據在啓動之前加載,因爲應根據這些配置選項來限制對某些組件的訪問。加載配置開始使用AOT

所以我創建了一個ConfigurationService獲得從後臺數據,我嘗試使用app_initializer根模塊中啓動應用程序前致電configurationservice。我已經設法在我幾個月前創建的角度應用程序(角度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;     
      } 
     );  
} 

這實際上得到使用configurationservice從後端數據,但在啓動應用程序之前不等待解決承諾。當用戶在主頁(每個人都可以訪問)啓動時運行,然後導航到非管理員用戶限制的組件。但是,當用戶刷新受限制的頁面時,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選項的人,這不適合我。

回答

3

隨着@DzmitryShylovich的幫助下對angular gitter channel,誰指出,呼籲從app.module.ts內的服務是遲到了,我應該從main.ts內調用服務文件,而不是,我設法解決我的問題。他向我提供了以下文字plnkr

這是我在我自己的解決方案對我所做的得到它的工作。

常數。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文件我稱之爲web服務,讓我的配置數據,解析數據並創建一個供應商傳入我的應用程序。我將憑據設置爲包含,因爲我在web服務上使用了Windows身份驗證,如果您沒有明確告訴提取憑據提供憑據,它將給出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取打字稿定義文件

npm install --save-dev @types/whatwg-fetch 

@DzmitryShylovich,謝謝你的幫助!

+0

如何在@ types/whatwg-fetch中解決重複標識符錯誤?似乎lib.d.ts現在包含獲取類型,因此在手動添加類型時會發生衝突。 –