定义全局常量

时间:2016-01-25 07:10:26

标签: typescript angular

在Angular 1.x中,您可以定义如下常量:

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

Angular2(使用TypeScript)的等价物是什么?

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

17 个答案:

答案 0 :(得分:224)

以下更改适用于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);
    }
}

答案 1 :(得分:150)

角度团队本身提供的配置解决方案可以找到here

以下是所有相关代码:

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

现在,您可以在不使用字符串名称的情况下将配置注入到任何地方,并使用您的接口进行静态检查。

您当然可以进一步分离界面和常量,以便能够在生产和开发中提供不同的值,例如

答案 2 :(得分:62)

在Angular2中,您有以下provide 定义,它允许您设置不同类型的依赖项:

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

答案 3 :(得分:48)

在Angular 4中,您可以使用环境类来保留所有全局变量。

默认情况下,您有environment.ts和environment.prod.ts。

例如

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

然后是您的服务:

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

答案 4 :(得分:40)

更新了Angular 4 +

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

例如

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

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

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

  • 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' ],
    };
    

应用程序中的用例

您可以将环境导入任何文件,例如服务clientUtilServices.ts

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

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

构建中的用例

打开角度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)
  }
 }

答案 5 :(得分:30)

虽然使用带有字符串常量的AppSettings类作为ApiEndpoint的方法有效,但它并不理想,因为在单元测试时我们无法将这个真正的ApiEndpoint交换为其他值。

我们需要能够将这个api端点注入到我们的服务中(考虑将服务注入到另一个服务中)。我们也不需要为此创建一个完整的类,我们要做的就是在我们的ApiEndpoint服务中注入一个字符串。要完成excellent answer by pixelbits,以下是有关如何在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...
}

答案 6 :(得分:28)

这是我最近对这种情况的经验:

  • @ 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@

  }

结果很干净,并且在控制台上没有任何警告感谢John Papa最近对此问题的评论:

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

密钥是在不同的文件接口中实现的。

答案 7 :(得分:15)

所有解决方案似乎都很复杂。我正在为这种情况寻找最简单的解决方案,我只想使用常量。常数很简单。有没有什么可以反对以下解决方案?

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

}

答案 8 :(得分:7)

只需使用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/'}), ...]);

答案 9 :(得分:4)

如果您正在使用我推荐的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)});
}

答案 10 :(得分:3)

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

答案 11 :(得分:2)

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

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

答案 12 :(得分:1)

我还有另一种定义全局常量的方法。因为如果我们在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
  }
}

在应用程序文件夹中,我添加文件夹configs / setting.json

setting.json中的内容

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

在应用模块中添加APP_INITIALIZER

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

通过这种方式,我可以更轻松地更改json文件中的值。 我也使用这种方式来不断出现错误/警告消息。

答案 13 :(得分:0)

在阅读了该线程的所有答案以及其他一些答案后,我想提供我这些天使用的解决方案。

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

// 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 来简化环境的创建,这样我就可以传递对象而不会弄乱构造函数参数并避免参数顺序问题,并且还使用 {{ 1}} 运算符。

??
// 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);

检查代码完成情况。 enter image description here

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',
    }
  }
];

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

对于那些想在构建后替换值的人。你能行的。这有点棘手,但是当您构建 Angular 应用程序时,环境数据会导出到 // 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}`); } } ,请看下一个屏幕截图。

enter image description here

只需在任何 IDE 中打开文件并找到 main.js,然后替换数据即可。

关于 Angular Universal 项目。构建 Angular Universal 项目后,它将导出 2 environment 一个用于服务器,一个用于浏览器,因此您必须同时更改两者。

答案 14 :(得分:0)

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

答案 15 :(得分:0)

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

虽然它作为提供者注册机制独立存在,但最好在相关module.value$provide.value)函数的上下文中理解。官方文档明确说明了用例:

  

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

将此与module.constant$provide.constant)的文档进行比较,该文档还明确说明了用例(强调我的):

  

使用$ injector注册常量服务,例如字符串,数字,数组,对象或函数。与值一样,不可能将其他服务注入常量。   但与值不同,常量可以注入模块配置函数(请参阅angular.Module),并且不能被AngularJS装饰器覆盖

因此,AngularJS constant函数不会在字段中通常理解的含义中提供常量。

这就是说对提供的对象的限制,以及之前通过$ injector注入的可用性,清楚地表明该名称是类比的。

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

export const π = 3.14159265;

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

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

的例子
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一样。

事情发生了变化......

答案 16 :(得分:-1)

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

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(){}或任何预定义方法中使用此功能。