在Angular 2中定义全局常量

在Angular 1.x中,你可以像这样定义常量:

angular.module('mainApp.config', []) .constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/') 

在Angular2(与打字稿)等价? 我只是不想在我的所有服务中重复一遍又一遍的API基础url。

Angular 2最终版本下面的变化对我有用:

 export class AppSettings { public static API_ENDPOINT='http://127.0.0.1:6666/api/'; } 

然后在服务中:

 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); } } 

angular度团队提供的configuration解决scheme可以在这里find。

我已经成功地实现了它,这里是所有相关的代码:

1)app.config.ts

 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)app.module.ts

 import { APP_CONFIG, AppConfig } from './app.config'; @NgModule({ providers: [ { provide: APP_CONFIG, useValue: AppConfig } ] }) 

3)your.service.ts

 import { APP_CONFIG, IAppConfig } from './app.config'; @Injectable() export class YourService { constructor(@Inject(APP_CONFIG) private config: IAppConfig) { // You can use config.apiEndpoint now } } 

现在,您可以在不使用string名称的情况下使用您的接口来进行静态检查。

你当然可以将接口和常量分开,以便能够在生产和开发中提供不同的值

在Angular2中,你有以下提供的定义,它允许你设置不同种类的依赖关系:

 provide(token: any, {useClass, useValue, useExisting, useFactory, deps, multi} 

比较angular1

app.service中的app.service等同于useClass中的useClass。

app.factory中的app.factory等同于useFactory中的useFactory。

app.constantapp.value已经被简化为使用更less约束的值。 即没有config块了。

app.provider – 在Angular 2中没有等价物。

例子

使用根注射器进行设置:

 bootstrap(AppComponent,[provide(API_ENDPOINT, { useValue='http://127.0.0.1:6666/api/' })]); 

或者使用组件的注入器进行设置:

 providers: [provide(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})] 

provide简短的手段:

 var injectorValue = Injector.resolveAndCreate([ new Provider(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'}) ]); 

使用喷油器,获得价值很简单:

 var endpoint = injectorValue.get(API_ENDPOINT); 

虽然使用一个带有一个string常量的AppSettings类作为ApiEndpoint的方法是有效的,但这并不理想,因为在unit testing时,我们无法将这个真正的ApiEndpointreplace为其他值。

我们需要能够将这个API端点注入到我们的服务中(想想把服务注入到另一个服务中)。 我们也不需要为此创build一个完整的类,我们所要做的就是向我们的ApiEndpoint的服务中注入一个string。 为了完成像素位的优秀回答, 下面是在Angular 2中如何完成的完整代码:

首先,我们需要告诉Angular如何在我们的应用程序中请求时提供我们的ApiEndpoint实例(将其视为注册依赖关系):

 bootstrap(AppComponent, [ HTTP_PROVIDERS, provide('ApiEndpoint', {useValue: 'http://127.0.0.1:6666/api/'}) ]); 

然后在服务中,我们这个ApiEndpoint注入到服务构造函数中,Angular将根据我们上面的注册为我们提供:

 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... } 

这是我最近的经验:

  • @ angular / cli:1.0.0
  • 节点:6.10.2
  • @ angular / core:4.0.0

我在这里按照官方和更新的文档:

https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#dependency-injection-tokens

似乎OpaqueToken现在已被弃用,我们必须使用InjectionToken ,所以这些是我的文件运行像一个魅力:

app-config.interface.ts

 export interface IAppConfig { STORE_KEY: string; } 

app-config.constants.ts

 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' ); 

app.module.ts

 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 {} 

my-service.service.ts

  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

关键是在不同的文件中实现接口。

所有的解决scheme似乎都很复杂。 我正在寻找这种情况下最简单的解决scheme,我只想使用常量。 常量很简单。 有什么和下面的解决scheme有关的吗?

app.const.ts

 'use strict'; export const dist = '../path/to/dist/'; 

app.service.ts

 import * as AppConst from '../app.const'; @Injectable() export class AppService { constructor ( ) { console.log('dist path', AppConst.dist ); } } 

感谢您的回复。

在Angular 4中,你可以使用环境类来保存所有的全局variables。

你有默认的environment.ts和environment.prod.ts。

例如

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

然后在您的服务:

 import { environment } from '../../environments/environment'; ... environment.apiUrl; 

只需使用一个Typescript常量

 export var API_ENDPOINT = 'http://127.0.0.1:6666/api/'; 

你可以在dependency injection器中使用它

 bootstrap(AppComponent, [provide(API_ENDPOINT, {useValue: 'http://127.0.0.1:6666/api/'}), ...]); 

在我的提供者中,我一直在做下面的事情:

 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' } } 

然后我可以在任何地方访问所有常量数据

 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) } } 

如果您使用的是我推荐的Webpack ,则可以为不同的环境设置常量。 当每个环境具有不同的常量值时,这是特别有价值的。

您的/config目录下可能会有多个webpack文件(例如,webpack.dev.js,webpack.prod.js等)。 那么你将有一个custom-typings.d.ts你将它添加到那里。 以下是每个文件中遵循的一般模式以及组件中的示例用法。

的WebPack。{ENV}的.js

 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) }), 

定制typings.d.ts

 declare var API_URL: string; declare var JWT_TOKEN_NAME: string; interface GlobalEnvironment { API_URL: string; JWT_TOKEN_NAME: string; } 

零件

 export class HomeComponent implements OnInit { api_url:string = API_URL; authToken: string = "Bearer " + localStorage.getItem(JWT_TOKEN_NAME)}); } 

使用在构build过程中生成的属性文件非常简单。 这是Angular CLI使用的方法。 为每个环境定义属性文件,并在构build过程中使用命令来确定将哪个文件复制到您的应用程序。 然后只需导入要使用的属性文件。

https://github.com/angular/angular-cli#build-targets-and-environment-files

你可以为你的全局variables创build一个类,然后像这样导出这个类:

 export class CONSTANT { public static message2 = [ { "NAME_REQUIRED": "Name is required" } ] public static message = { "NAME_REQUIRED": "Name is required", } } 

在创build和导出CONSTANT类之后,您应该在要使用的类中导入此类,如下所示:

 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); } } 

你可以在constructorngOnInit(){} ,或者在任何预定义的方法中使用。

AngularJS的module.constant没有定义标准意义上的常量。

虽然它作为一个提供者注册机制自己站立,但最好在相关的module.value$provide.value )函数的上下文中理解。 官方文件明确指出了用例:

用$注入器注册一个值服务,如string,数字,数组,对象或函数。 这是注册服务的简称,其提供者的$ get属性是不带参数的工厂函数,并返回值服务。 这也意味着无法将其他服务注入价值服务。

把这个和module.constant$provide.constant module.constant )的文档比较一下,它也清楚地说明了用例(重点是我的):

用$注入器注册一个常量服务,如string,数字,数组,对象或函数。 像价值一样,不可能将其他服务注入到一个常量中。 但是与value不同的是, 一个常量可以被注入到一个模块configuration函数中(参见angular.Module),AngularJS装饰器不能覆盖它

因此,AngularJS constant函数不能提供本领域术语通常理解的常数。

这就是说,对提供的对象施加的限制,以及通过$注入器提供的更早的可用性,清楚地表明这个名字被用于类比。

如果您想在AngularJS应用程序中使用一个实际的常量,那么您应该像在任何JavaScript程序中一样“提供”

 export const π = 3.14159265; 

在Angular 2中,同样的技术也是适用的。

Angular 2应用程序没有像AngularJS应用程序那样的configuration阶段。 此外,没有服务修饰器机制( AngularJS装饰器 ),但这并不特别令人惊讶,因为它们彼此之间有多么不同。

的例子

 angular .module('mainApp.config', []) .constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/'); 

是含糊不清的,并且稍微$provide.constant ,因为$provide.constant被用来指定一个偶然也是常量的对象。 你可能已经写了

 export const apiEndpoint = 'http://127.0.0.1:6666/api/'; 

所有人都可以改变。

现在,嘲笑常数的可testing性的论证被削弱了,因为它从字面上看并没有改变。

一个不嘲笑π。

当然,您的应用程序特定的语义可能是您的端点可能会更改,或者您的API可能具有非透明的故障转移机制,所以在某些情况下API端点更改是合理的。

但是在这种情况下,将其作为单个URL的string文字表示forms提供给constant函数将不起作用。

一个更好的论点,可能与AngularJS $provide.constant函数存在的原因更加一致的是,当AngularJS被引入时,JavaScript没有标准的模块概念。 在这种情况下,全局variables将被用来共享值,可变的或不可变的,并且使用全局variables是有问题的。

也就是说,通过一个框架提供这样的东西增加了与该框架的耦合。 它还将angular度特定的逻辑与可以在任何其他系统中工作的逻辑混合在一起。

这并不是说这是一个错误的或有害的方法,但个人而言,如果我想要一个Angular 2应用程序中的常量 ,我会写

 export const π = 3.14159265; 

就像我使用AngularJS一样。

事情变化越多…

Angular4的一个方法是在模块级定义一个常量:

 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 { } 

然后,在您的服务:

 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); } }