定义全局常量

在Angular 1中。X你可以这样定义常量:

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

在Angular中(使用TypeScript)会是什么?

我只是不想在我的所有服务中一遍又一遍地重复API基url。

414882 次浏览

只需使用Typescript常量

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

你可以在依赖注入器中使用

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

在Angular2中,你有下面的提供定义,它允许你设置不同类型的依赖:

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

与Angular 1的比较

Angular1中的app.service等价于Angular2中的useClass

Angular1中的app.factory等价于Angular2中的useFactory

app.constantapp.value被简化为useValue,约束更少。即不再有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);

以下改动对我来说在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);
}
}

虽然有一个AppSettings类和一个字符串常量作为ApiEndpoint的方法是可行的,但这并不理想,因为我们不能在单元测试时将这个真正的ApiEndpoint交换为其他一些值。

我们需要能够将这个api端点注入到我们的服务中(想象一下将一个服务注入到另一个服务中)。我们也不需要为此创建一个完整的类,我们所要做的只是将一个字符串注入到我们的服务中,作为我们的ApiEndpoint。为了完成pixelbits回答得很好,下面是在Angular 2中如何完成它的完整代码:

首先,我们需要告诉Angular,当我们在应用中请求ApiEndpoint的实例时,如何提供它(可以把它看作是注册一个依赖项):

bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide('ApiEndpoint', {useValue: 'http://127.0.0.1:6666/api/'})
]);
< p > < br > 然后在服务中,我们注入这个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使用的方法。为每个环境定义一个属性文件,并在构建期间使用命令来确定将哪个文件复制到应用程序中。然后简单地导入属性文件来使用。

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

为Angular 4+更新

现在,如果你的项目是通过angular-cli生成的,我们可以简单地使用angular提供的默认环境文件。

例如

在环境文件夹中创建以下文件

  • environment.prod.ts
  • environment.qa.ts
  • environment.dev.ts

每个文件都可以保存相关的代码更改,例如:

  • < p > environment.prod.ts

    export const environment = {
    production: true,
    apiHost: 'https://api.somedomain.com/prod/v1/',
    CONSUMER_KEY: 'someReallyStupidTextWhichWeHumansCantRead',
    codes: [ 'AB', 'AC', 'XYZ' ],
    };
    
  • environment.qa.ts

    export const environment = {
    production: false,
    apiHost: 'https://api.somedomain.com/qa/v1/',
    CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead',
    codes: [ 'AB', 'AC', 'XYZ' ],
    };
    
  • environment.dev.ts

    export const environment = {
    production: false,
    apiHost: 'https://api.somedomain.com/dev/v1/',
    CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead',
    codes: [ 'AB', 'AC', 'XYZ' ],
    };
    

Use-case in application

You can import environments into any file such as services clientUtilServices.ts

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

getHostURL(): string {
return environment.apiHost;
}

构建中的用例

打开你的angular cli文件.angular-cli.json,在"apps": [{...}]中添加以下代码

 "apps":[{
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts",
"qa": "environments/environment.qa.ts",
}
}
]

如果你想要为生产构建,运行ng build --env=prod,它将从environment.prod.ts读取配置,同样的方法也可以用于qadev

##老答案

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

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

angular团队提供的配置解决方案可以在在这里中找到。

以下是所有相关代码:

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

现在您可以在任何地方注入配置,而无需使用字符串名称,并使用您的接口进行静态检查。

当然,您可以进一步分离接口和常数,以便在生产和开发中提供不同的值。

如果你正在使用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)
}),

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

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

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


public static message = {
"NAME_REQUIRED": "Name is required",
}
}

在创建并导出你的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(){}中使用它,也可以在任何预定义方法中使用。

以下是我最近在这种情况下的经验:

  • @angular / cli: 1.0.0
  • 节点:6.10.2
  • @angular /核心:4.0.0

我在这里遵循了官方和更新的文档:

< a href = " https://angular.io/docs/ts/latest/guide/dependency-injection.html !# dependency-injection-tokens noreferrer“rel = > 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@


}

结果是干净的,主机上没有任何警告,这要感谢John Papa最近在这个问题上的评论:

https://github.com/angular/angular-cli/issues/2034

该键在接口的另一个文件中实现。

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

虽然它是一个独立的提供者注册机制,但最好在相关的module.value ($provide.value)函数的上下文中理解它。官方文档清楚地陈述了用例:

用$injector注册一个值服务,比如一个字符串、一个数字、一个数组、一个对象或一个函数。这是注册服务的缩写,其中其提供者的$get属性是一个不接受参数并返回值服务的工厂函数。这也意味着不可能将其他服务注入到价值服务中。

将其与module.constant ($provide.constant)的文档进行比较,后者也清楚地说明了用例(重点是我的):

向$injector注册一个常量服务,比如字符串、数字、数组、对象或函数。与值一样,不可能将其他服务注入到常量中。 但与value不同的是,常量可以被注入到模块的配置函数中(参见angular.Module),而且它不能被AngularJS的装饰器覆盖.

. value

因此,AngularJS constant函数没有提供字段中术语的一般理解意义上的常量。

也就是说,对所提供的对象施加的限制,以及它之前通过$注入器的可用性,清楚地表明该名称是类推使用的。

如果你想在AngularJS应用程序中有一个实际的常量,你可以像在任何JavaScript程序中一样“提供”一个

export const π = 3.14159265;

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

Angular 2应用程序没有AngularJS应用程序那样的配置阶段。此外,没有服务装饰器机制(AngularJS装饰),但考虑到它们彼此之间的差异,这并不特别令人惊讶。

例如

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

因为$provide.constant被用来指定一个对象,而这个对象顺便说一下也是一个常量。你还不如写信算了

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

因为任何一方都可以改变。

现在关于可测性的争论,嘲笑常数,被削弱了,因为它字面上是不变的。

不模拟π。

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

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

一个更好的论据,可能是一个更符合AngularJS $provide.constant函数存在的原因,当AngularJS被引入时,JavaScript还没有标准模块的概念。在这种情况下,全局变量将用于共享可变或不可变的值,使用全局变量是有问题的。

也就是说,通过框架提供这样的东西可以增加与该框架的耦合。它还将特定于Angular的逻辑与适用于任何其他系统的逻辑混合在一起。

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

export const π = 3.14159265;

就像我使用AngularJS一样。

事情改变得越多……

所有的解决方案似乎都很复杂。我在寻找这种情况下最简单的解我只想用常数。常量很简单。是否有反对以下解决方案的意见?

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中,你可以使用环境类来保存所有的全局变量。

你有环境。Ts和environment. products . Ts。

例如

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

在你的服务中:

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

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

在Angular 2中创建应用范围常量的最佳方法是使用environment。ts文件。声明这些常量的好处是,您可以根据环境改变它们,因为每个环境可以有不同的环境文件。

我有另一种定义全局常数的方法。因为如果我们在ts文件中定义,如果在生产模式中构建,就不容易找到常数来改变值。

export class SettingService  {


constructor(private http: HttpClient) {


}


public getJSON(file): Observable<any> {
return this.http.get("./assets/configs/" + file + ".json");
}
public getSetting(){
// use setting here
}
}

在app文件夹中,我添加文件夹configs/setting.json

设置.json中的内容

{
"baseUrl": "http://localhost:52555"
}

在app模块中添加APP_INITIALIZER

   {
provide: APP_INITIALIZER,
useFactory: (setting: SettingService) => function() {return setting.getSetting()},
deps: [SettingService],
multi: true
}

用这种方式,我可以改变json文件的值更容易。 对于常量错误/警告消息,我也使用这种方法

在阅读了这个帖子和其他一些帖子的所有答案后,我想提供我这些天正在使用的解决方案。

首先,我必须为环境添加一个类。这样,我就实现了属性的数据类型,因此使用起来很容易。此外,我还可以将默认数据绑定到我的环境,这样我就可以在所有环境之间共享公共数据。有时我们有一些在所有环境中具有相同值的变量(例如站点名称),并且我们不希望每次都更改到所有环境。

// environments\ienvironments.ts


export class IEnvironment implements IEnvironmentParams {
public production: boolean;
public basicURL: string = 'https://www.someawesomedomain.com';
public siteName: string = 'My awesome site';


constructor(params: IEnvironmentParams) {
this.production = params.production ?? false;
this.basicURL = params.basicURL ?? this.basicURL;
this.siteName = params.siteName ?? this.siteName;
}
}


export interface IEnvironmentParams {
production: boolean;
basicURL?: string;
siteName?: string;
}

注意,我正在使用IEnvironmentParams来简化环境的创建,这样我就可以传递一个对象,而不会混淆构造函数参数,避免参数顺序问题,还可以使用??操作符提供所需的默认值功能。

// environments\environment.prod.ts


import {IEnvironment, IEnvironmentParams} from "./ienvironment";


const params: IEnvironmentParams = {
production: true
};


export const environment: IEnvironment = new IEnvironment(params);
// environments\environment.ts


import {IEnvironment, IEnvironmentParams} from "./ienvironment";


const params: IEnvironmentParams = {
production: false
};


export const environment: IEnvironment = new IEnvironment(params);

用法示例

import {environment} from "../environments/environment";




// app-routing.module.ts


const routes: Routes = [
{
path: '', component: HomeComponent,
data: {
title: `${environment.siteName} | Home page title!`,
description: 'some page description',
}
}
];

检查代码完成情况。 enter image description here < / p >

// home.component.ts


@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent {


constructor() {
console.log(`home component constructor - showing evironment.siteName - ${environment.siteName}`);
}
}

你可以在任何你想要的地方使用它,类、服务、指令、组件等等。

对于那些想知道在构建之后替换值的人。你能做到的。这有点棘手,但当你构建一个Angular应用时,环境数据会被导出到main.js,看看下面的截图。

enter image description here

只需在任何IDE中打开文件并找到environment,然后替换数据。

关于Angular Universal项目。当Angular Universal项目被构建时,它会导出2个main.js,一个用于服务器,一个用于浏览器,所以你必须对两者都进行更改。