Define global constants
在角度1.x中,可以这样定义常量:
1 2 | angular.module('mainApp.config', []) .constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/') |
在Angular2中(使用typescript)的等效值是多少?
我只是不想在我的所有服务中反复地重复API基URL。
以下更改适用于Angular2最终版本:
1 2 3 | export class AppSettings { public static API_ENDPOINT='http://127.0.0.1:6666/api/'; } |
然后在服务中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import {Http} from 'angular2/http'; import {Message} from '../models/message'; import {Injectable} from 'angular2/core'; import {Observable} from 'rxjs/Observable'; import {AppSettings} from '../appSettings'; import 'rxjs/add/operator/map'; @Injectable() export class MessageService { constructor(private http: Http) { } getMessages(): Observable<Message[]> { return this.http.get(AppSettings.API_ENDPOINT+'/messages') .map(response => response.json()) .map((messages: Object[]) => { return messages.map(message => this.parseData(message)); }); } private parseData(data): Message { return new Message(data); } } |
。
角团队提供的配置解决方案可以在这里找到。
以下是所有相关代码:
1)应用配置TS
1 2 3 4 5 6 7 8 9 10 11 | import { OpaqueToken } from"@angular/core"; export let APP_CONFIG = new OpaqueToken("app.config"); export interface IAppConfig { apiEndpoint: string; } export const AppConfig: IAppConfig = { apiEndpoint:"http://localhost:15422/api/" }; |
号
2)应用模块TS
1 2 3 4 5 6 7 | import { APP_CONFIG, AppConfig } from './app.config'; @NgModule({ providers: [ { provide: APP_CONFIG, useValue: AppConfig } ] }) |
号
3)您的.service.ts
1 2 3 4 5 6 7 8 9 | import { APP_CONFIG, IAppConfig } from './app.config'; @Injectable() export class YourService { constructor(@Inject(APP_CONFIG) private config: IAppConfig) { // You can use config.apiEndpoint now } } |
现在,您可以在任何地方注入配置,而无需使用字符串名称,也可以使用接口进行静态检查。
当然,您可以进一步分离接口和常量,以便在生产和开发中提供不同的值,例如
在Angular2中,您有以下提供的定义,允许您设置不同类型的依赖项:
1 | provide(token: any, {useClass, useValue, useExisting, useFactory, deps, multi} |
与角度1比较
角1中的
角1中的
示例
要设置根部喷油器:
1 | bootstrap(AppComponent,[provide(API_ENDPOINT, { useValue='http://127.0.0.1:6666/api/' })]); |
。
或使用组件的喷油器进行设置:
1 | providers: [provide(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})] |
1 2 3 | var injectorValue = Injector.resolveAndCreate([ new Provider(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'}) ]); |
。
使用注入器,很容易获得值:
1 | var endpoint = injectorValue.get(API_ENDPOINT); |
。
在Angular4中,您可以使用环境类来保存所有全局变量。
默认情况下,您有environment.ts和environment.prod.ts。
例如
1 2 3 4 | export const environment = { production: false, apiUrl: 'http://localhost:8000/api/' }; |
。
然后为您服务:
1 2 3 | import { environment } from '../../environments/environment'; ... environment.apiUrl; |
更新为角4+
现在我们可以简单地使用环境文件,如果您的项目是通过angular cli生成的,那么angular将提供默认的环境文件。
例如
在环境文件夹中创建以下文件
- 埃多克斯1〔10〕
- 江户十一〔11〕。
- 埃多克斯1〔12〕
每个文件都可以保存相关的代码更改,例如:
埃多克斯1〔10〕
1
2
3
4
5
6export const environment = {
production: true,
apiHost: 'https://api.somedomain.com/prod/v1/',
CONSUMER_KEY: 'someReallyStupidTextWhichWeHumansCantRead',
codes: [ 'AB', 'AC', 'XYZ' ],
};号
江户十一〔11〕。
1
2
3
4
5
6export const environment = {
production: false,
apiHost: 'https://api.somedomain.com/qa/v1/',
CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead',
codes: [ 'AB', 'AC', 'XYZ' ],
};号
埃多克斯1〔12〕
1
2
3
4
5
6export const environment = {
production: false,
apiHost: 'https://api.somedomain.com/dev/v1/',
CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead',
codes: [ 'AB', 'AC', 'XYZ' ],
};号
应用中的用例
您可以将环境导入任何文件,如services
埃多克斯1〔17〕
1 2 3 | getHostURL(): string { return environment.apiHost; } |
号构建中的用例
打开angular cli文件
1 2 3 4 5 6 7 8 | "apps":[{ "environments": { "dev":"environments/environment.ts", "prod":"environments/environment.prod.ts", "qa":"environments/environment.qa.ts", } } ] |
号
如果您想为生产而构建,运行
我在我的供应商那里做了如下的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 | import {Injectable} from '@angular/core'; @Injectable() export class ConstantService { API_ENDPOINT :String; CONSUMER_KEY : String; constructor() { this.API_ENDPOINT = 'https://api.somedomain.com/v1/'; this.CONSUMER_KEY = 'someReallyStupidTextWhichWeHumansCantRead' } } |
号
然后我可以在任何地方访问所有常量数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import {Injectable} from '@angular/core'; import {Http} from '@angular/http'; import 'rxjs/add/operator/map'; import {ConstantService} from './constant-service'; //This is my Constant Service @Injectable() export class ImagesService { constructor(public http: Http, public ConstantService: ConstantService) { console.log('Hello ImagesService Provider'); } callSomeService() { console.log("API_ENDPOINT:",this.ConstantService.API_ENDPOINT); console.log("CONSUMER_KEY:",this.ConstantService.CONSUMER_KEY); var url = this.ConstantService.API_ENDPOINT; return this.http.get(url) } } |
号
虽然使用字符串常量作为apiendpoint的appsettings类的方法是可行的,但这并不理想,因为在单元测试时,我们无法将这个真正的apiendpoint替换为其他一些值。
我们需要能够将这个API端点注入到我们的服务中(考虑将服务注入到另一个服务中)。我们也不需要为此创建一个完整的类,我们只需要向我们的服务中注入一个字符串,作为我们的APIEndpoint。为了完成pixelbits的完美答案,以下是关于如何在角度2中完成的完整代码:
首先,我们需要告诉Angular,当我们在应用程序中请求apiendpoint时,如何提供它的实例(将其视为注册依赖项):
1 2 3 4 | bootstrap(AppComponent, [ HTTP_PROVIDERS, provide('ApiEndpoint', {useValue: 'http://127.0.0.1:6666/api/'}) ]); |
然后在服务中,我们将这个apiendpoint注入到服务构造函数中,Angular将根据上面的注册为我们提供它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import {Http} from 'angular2/http'; import {Message} from '../models/message'; import {Injectable, Inject} from 'angular2/core'; // * We import Inject here import {Observable} from 'rxjs/Observable'; import {AppSettings} from '../appSettings'; import 'rxjs/add/operator/map'; @Injectable() export class MessageService { constructor(private http: Http, @Inject('ApiEndpoint') private apiEndpoint: string) { } getMessages(): Observable<Message[]> { return this.http.get(`${this.apiEndpoint}/messages`) .map(response => response.json()) .map((messages: Object[]) => { return messages.map(message => this.parseData(message)); }); } // the rest of the code... } |
。
这是我最近在这种情况下的经验:
- @角度/cli:1.0.0
- 节点:6.10.2
- @角度/核心:4.0.0
我在这里跟踪了官方和更新的文档:
https://angular.io/docs/ts/latest/guide/dependency injection.html!#依赖注入令牌
似乎opaquetoken现在被弃用了,我们必须使用injectiontoken,所以这些是我的文件,运行起来像个符咒:
埃多克斯1〔5〕
1 2 3 4 5 | export interface IAppConfig { STORE_KEY: string; } |
。
埃多克斯1〔6〕
1 2 3 4 5 6 7 8 9 10 | import { InjectionToken } from"@angular/core"; import { IAppConfig } from"./app-config.interface"; export const APP_DI_CONFIG: IAppConfig = { STORE_KEY: 'l@_list@' }; export let APP_CONFIG = new InjectionToken< IAppConfig >( 'app.config' ); |
。
江户十一〔七〕号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { APP_CONFIG, APP_DI_CONFIG } from"./app-config/app-config.constants"; @NgModule( { declarations: [ ... ], imports: [ ... ], providers: [ ..., { provide: APP_CONFIG, useValue: APP_DI_CONFIG } ], bootstrap: [ ... ] } ) export class AppModule {} |
埃多克斯1〔8〕
1 2 3 4 5 6 7 | constructor( ..., @Inject( APP_CONFIG ) private config: IAppConfig) { console.log("This is the App's Key:", this.config.STORE_KEY); //> This is the App's Key: l@_list@ } |
。
结果是干净的,控制台上没有警告。感谢约翰·帕帕最近在这个问题上的评论:
https://github.com/angular/angular-cli/issues/2034
该键在另一个文件中实现接口。
所有的解决方案似乎都很复杂。我在为这个例子寻找最简单的解决方案,我只想使用常量。常量很简单。有什么反对以下解决方案的吗?
应用常数ts
1 2 3 | 'use strict'; export const dist = '../path/to/dist/'; |
应用服务.ts
1 2 3 4 5 6 7 8 9 10 11 | import * as AppConst from '../app.const'; @Injectable() export class AppService { constructor ( ) { console.log('dist path', AppConst.dist ); } } |
。
只需使用typescript常量
1 | export var API_ENDPOINT = 'http://127.0.0.1:6666/api/'; |
您可以在依赖注入器中使用它
1 | bootstrap(AppComponent, [provide(API_ENDPOINT, {useValue: 'http://127.0.0.1:6666/api/'}), ...]); |
号
如果您使用的是Webpack,我建议您可以为不同的环境设置常量。当您在每个环境中具有不同的常量值时,这一点尤其重要。
您的
webpack.env.js
1 2 3 4 5 6 7 8 9 | const API_URL = process.env.API_URL = 'http://localhost:3000/'; const JWT_TOKEN_NAME ="id_token"; ... plugins: [ // NOTE: when adding more properties, make sure you include them in custom-typings.d.ts new DefinePlugin({ 'API_URL': JSON.stringify(API_URL), 'JWT_TOKEN_NAME': JSON.stringify(JWT_TOKEN_NAME) }), |
定制类型.d.ts
1 2 3 4 5 6 | declare var API_URL: string; declare var JWT_TOKEN_NAME: string; interface GlobalEnvironment { API_URL: string; JWT_TOKEN_NAME: string; } |
号
组件
1 2 3 4 | export class HomeComponent implements OnInit { api_url:string = API_URL; authToken: string ="Bearer" + localStorage.getItem(JWT_TOKEN_NAME)}); } |
角度4的一种方法是在模块级定义一个常量:
1 2 3 4 5 6 7 8 9 10 11 12 | const api_endpoint = 'http://127.0.0.1:6666/api/'; @NgModule({ declarations: [AppComponent], bootstrap: [AppComponent], providers: [ MessageService, {provide: 'API_ENDPOINT', useValue: api_endpoint} ] }) export class AppModule { } |
。
那么,为您服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import {Injectable, Inject} from '@angular/core'; @Injectable() export class MessageService { constructor(private http: Http, @Inject('API_ENDPOINT') private api_endpoint: string) { } getMessages(): Observable<Message[]> { return this.http.get(this.api_endpoint+'/messages') .map(response => response.json()) .map((messages: Object[]) => { return messages.map(message => this.parseData(message)); }); } private parseData(data): Message { return new Message(data); } } |
我有另一种定义全局常量的方法。因为如果我们在TS文件中定义,那么在生产模式中构建,就不容易找到常量来更改值。
1 2 3 4 5 6 7 8 9 10 11 12 13 | export class SettingService { constructor(private http: HttpClient) { } public getJSON(file): Observable { return this.http.get("./assets/configs/" + file +".json"); } public getSetting(){ // use setting here } } |
在app文件夹中,我添加文件夹configs/setting.json
setting.json中的内容
1 2 3 | { "baseUrl":"http://localhost:52555" } |
号
在应用程序模块中添加应用程序初始值设定项
1 2 3 4 5 6 | { provide: APP_INITIALIZER, useFactory: (setting: SettingService) => function() {return setting.getSetting()}, deps: [SettingService], multi: true } |
通过这种方式,我可以更容易地更改JSON文件中的值。我也用这种方式来处理持续的错误/警告消息。
使用在构建过程中生成的属性文件非常简单。这是Angular CLI使用的方法。为每个环境定义一个属性文件,并在生成期间使用一个命令来确定将哪个文件复制到应用程序。然后简单地导入要使用的属性文件。
https://github.com/angular/angular cli构建目标和环境文件
AngularJS的
虽然它本身是一个提供者注册机制,但最好在相关的
Register a value service with the $injector, such as a string, a number, an array, an object or a function. This is short for registering a service where its provider's $get property is a factory function that takes no arguments and returns the value service. That also means it is not possible to inject other services into a value service.
号
将其与
Register a constant service with the $injector, such as a string, a number, an array, an object or a function. Like the value, it is not possible to inject other services into a constant.
But unlike value, a constant can be injected into a module configuration function (see angular.Module) and it cannot be overridden by an AngularJS decorator.
号
因此,AngularJS-
这就是说,对所提供对象的限制,以及通过$injector提供的早期可用性,都清楚地表明这个名称是通过类比来使用的。
如果您希望在AngularJS应用程序中有一个实际的常量,那么您可以像在任何JavaScript程序中那样"提供"一个常量。
1 | export const π = 3.14159265; |
在角2中,同样的技术也适用。
Angular2应用程序没有与AngularJS应用程序相同的配置阶段。此外,还没有服务装饰器机制(angularjs decorator),但考虑到它们之间的差异,这并不奇怪。
示例
1 2 3 | angular .module('mainApp.config', []) .constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/'); |
号
有点武断,有点令人不快,因为
1 | export const apiEndpoint = 'http://127.0.0.1:6666/api/'; |
因为任何一个都可以改变。
现在,对可测试性的争论,嘲弄常量,因为它实际上没有改变。
一个人不会嘲笑π。
当然,特定于应用程序的语义可能是端点可能发生更改,或者您的API可能具有不透明的故障转移机制,因此在某些情况下,API端点可能发生更改是合理的。
但是在这种情况下,将它作为单个
一个更好的论据,可能还有一个与AngularJS
这就是说,通过框架提供类似这样的东西会增加与该框架的耦合。它还混合了角度特定的逻辑和任何其他系统都可以工作的逻辑。
这并不是说这是一个错误或有害的方法,但就个人而言,如果我想要一个角2应用中的常量,我会写
1 | export const π = 3.14159265; |
就像我会使用安古拉基一样。
事情越变…
在Angular2中创建应用程序范围常量的最佳方法是使用environment.ts文件。声明这些常量的好处是,您可以根据环境改变它们,因为每个环境都可以有不同的环境文件。
您可以为全局变量生成一个类,然后像这样导出此类:
1 2 3 4 5 6 7 8 9 | export class CONSTANT { public static message2 = [ {"NAME_REQUIRED":"Name is required" } ] public static message = { "NAME_REQUIRED":"Name is required", } } |
。
在创建和导出您的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import { Component, OnInit } from '@angular/core'; import { CONSTANT } from '../../constants/dash-constant'; @Component({ selector : 'team-component', templateUrl: `../app/modules/dashboard/dashComponents/teamComponents/team.component.html`, }) export class TeamComponent implements OnInit { constructor() { console.log(CONSTANT.message2[0].NAME_REQUIRED); console.log(CONSTANT.message.NAME_REQUIRED); } ngOnInit() { console.log("oninit"); console.log(CONSTANT.message2[0].NAME_REQUIRED); console.log(CONSTANT.message.NAME_REQUIRED); } } |
您可以在