2017-04-03 47 views
23

我想添加一個App Settings部分到我的應用程序,它將包含一些常量和預定義的值。App.settings - 角度的方式?

我已閱讀this answer其中使用OpaqueToken但它已在Angular中棄用。這article解釋的差異,但它沒有提供一個完整的例子,我的嘗試是不成功的。

這裏是我試過(我不知道這是否是正確的方式):

//ServiceAppSettings.ts 

import {InjectionToken, OpaqueToken} from "@angular/core"; 

const CONFIG = { 
    apiUrl: 'http://my.api.com', 
    theme: 'suicid-squad', 
    title: 'My awesome app' 
}; 
const FEATURE_ENABLED = true; 
const API_URL = new InjectionToken<string>('apiUrl'); 

而這正是我想用這些consts組件:

//MainPage.ts 

import {...} from '@angular/core' 
import {ServiceTest} from "./ServiceTest" 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <span>Hi</span> 
    ` , providers: [ 
    { 
     provide: ServiceTest, 
     useFactory: (apiUrl) => { 
     // create data service 
     }, 
     deps: [ 

     new Inject(API_URL) 
     ] 
    } 
    ] 
}) 
export class MainPage { 


} 

但它不起作用,我得到錯誤。

問:

我怎麼能消費 「app.settings」 的價值觀的角度呢?

plunker

NB當然,我可以創造注射服務,並把它放在NgModule的供應商,但正如我說我想InjectionToken,角度的方式來做到這一點。

+0

你可以檢查我的答案[這裏](http://stackoverflow.com/questions/34986922/ define-global-constants-in-angular-2/43439599#43439599)基於當前官方文檔 – JavierFuentes

+0

@ javier no。如果兩個供應商提供相同的名稱,則您的鏈接有問題,因此您現在有問題。 Entring opaquetoken –

+0

你知道[OpaqueToken已被棄用]。 (https://angular.io/api/core/OpaqueToken)[本文](https://blog.thoughtram.io/angular/2016/05/23/opaque-tokens-in-angular-2.html )談到如何防止角提供商名稱衝突 – JavierFuentes

回答

24

我想通了如何與InjectionTokens做到這一點(見下面的例子),如果你的項目是使用內置的Angular CLI您可以使用/environments中發現的環境文件靜態application wide settings像一個API端點,但根據您的項目因爲環境文件只是對象文字,而使用InjectionToken的可注入配置可以使用環境變量,並且由於它是一個類,可以根據應用程序中的其他因素對其應用邏輯進行配置,如初始http請求數據,子域等。

注入令牌示例

/app/app-config.module.ts

import { NgModule, InjectionToken } from '@angular/core'; 
import { environment } from '../environments/environment'; 

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config'); 

export class AppConfig { 
    apiEndpoint: string; 
} 

export const APP_DI_CONFIG: AppConfig = { 
    apiEndpoint: environment.apiEndpoint 
}; 

@NgModule({ 
    providers: [{ 
    provide: APP_CONFIG, 
    useValue: APP_DI_CONFIG 
    }] 
}) 
export class AppConfigModule { } 

/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 

import { AppConfigModule } from './app-config.module'; 

@NgModule({ 
    declarations: [ 
    // ... 
    ], 
    imports: [ 
    // ... 
    AppConfigModule 
    ], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

現在你只需DI它到任何組件,服務等:

/app/core/auth.service.ts

import { Injectable, Inject } from '@angular/core'; 
import { Http, Response } from '@angular/http'; 
import { Router } from '@angular/router'; 
import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/observable/throw'; 

import { APP_CONFIG, AppConfig } from '../app-config.module'; 
import { AuthHttp } from 'angular2-jwt'; 

@Injectable() 
export class AuthService { 

    constructor(
    private http: Http, 
    private router: Router, 
    private authHttp: AuthHttp, 
    @Inject(APP_CONFIG) private config: AppConfig 
) { } 

    /** 
    * Logs a user into the application. 
    * @param payload 
    */ 
    public login(payload: { username: string, password: string }) { 
    return this.http 
     .post(`${this.config.apiEndpoint}/login`, payload) 
     .map((response: Response) => { 
     const token = response.json().token; 
     sessionStorage.setItem('token', token); // TODO: can this be done else where? interceptor 
     return this.handleResponse(response); // TODO: unset token shouldn't return the token to login 
     }) 
     .catch(this.handleError); 
    } 

    // ... 
} 

然後,您也可以使用導出的AppConfig鍵入檢查配置。

+0

不,但您可以將第一部分複製並粘貼到文件中,將其導入到您的app.module.ts文件中,然後將其輸入到任意位置並將其輸出到控制檯。我會花更長的時間來設置這個蹲在那裏,然後它會做這些步驟。 – mtpultz

+0

哦,我以爲你已經有一個這樣的運動員:-)謝謝。 –

+0

對於那些想要:https://plnkr.co/edit/2YMZk5mhP1B4jTgA37B8?p=preview –

70

如果使用,還有另一種選擇:

角CLI提供環境文件src/environments(默認設置會被environment.ts(DEV)和environment.prod.ts(生產))。

請注意,您需要提供所有environment.*文件中的配置參數,例如,

environment.ts

export const environment = { 
    production: false, 
    apiEndpoint: 'http://localhost:8000/api/v1' 
}; 

environment.prod.ts

export const environment = { 
    production: true, 
    apiEndpoint: '__your_production_server__' 
}; 

並在您的服務中使用它們(正確的環境文件是自動選擇):

api.service.ts

// ... other imports 
import { environment } from '../../environments/environment'; 

@Injectable() 
export class ApiService {  

    public apiRequest(): Observable<MyObject[]> { 
    const path = environment.apiEndpoint + `/objects`; 
    // ... 
    } 

// ... 
} 
+2

這應該是個很好的答案;) – Deunz

+0

這是一個簡單而優雅的解決方案。謝謝@tilo –

+0

其工作正常。但移動構建時,它也改變爲bundle.I應改變我的服務器配置不在代碼中後移到生產 – kamalav

0

這裏是我的解決方案,從以.json負載允許修改,而不必重建

import { Injectable, Inject } from '@angular/core'; 
import { Http } from '@angular/http'; 
import { Observable } from 'rxjs/Observable'; 
import { Location } from '@angular/common'; 

@Injectable() 
export class ConfigService { 

    private config: any; 

    constructor(private location: Location, private http: Http) { 
    } 

    async apiUrl(): Promise<string> { 
     let conf = await this.getConfig(); 
     return Promise.resolve(conf.apiUrl); 
    } 

    private async getConfig(): Promise<any> { 
     if (!this.config) { 
      this.config = (await this.http.get(this.location.prepareExternalUrl('/assets/config.json')).toPromise()).json(); 
     } 
     return Promise.resolve(this.config); 
    } 
} 

和config.json

{ 
    "apiUrl": "http://localhost:3000/api" 
}