在Angular 2中定义全局常量

And*_*ijo 240 typescript angular

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

angular.module('mainApp.config', [])
.constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/')
Run Code Online (Sandbox Code Playgroud)

Angular2(使用Typescript)中的等价物是什么?我只是不想在我的所有服务中一遍又一遍地重复API基本URL.

And*_*ijo 246

以下更改适用于Angular 2最终版本:

export class AppSettings {
   public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}
Run Code Online (Sandbox Code Playgroud)

然后在服务中:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为“AppSettings”类应该是抽象的,“API_ENDPOINT”成员应该是“readonly”。 (2认同)

Ily*_*dik 156

角度团队本身提供的配置解决方案可以在这里找到.

以下是所有相关代码:

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/"    
};
Run Code Online (Sandbox Code Playgroud)

2)app.module.ts

import { APP_CONFIG, AppConfig } from './app.config';

@NgModule({
    providers: [
        { provide: APP_CONFIG, useValue: AppConfig }
    ]
})
Run Code Online (Sandbox Code Playgroud)

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
    }   
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这些解决方案都没有,即使是团队推荐的方法看起来也很优雅.为什么在Angular 2中尝试创建常量是一个繁琐的过程?你看不出Angular1是如何制作它的吗?为什么一切乱七八糟? (38认同)
  • 对于那些得到这个答案的人来说,Angular v4中的OpaqueToken对于InjectionToken是"弃用的" - https://blog.thoughtram.io/angular/2016/05/23/opaque-tokens-in-angular-2.html (29认同)
  • 它仅在我没有在服务的构造函数中指定类型时才有效.所以当我做构造函数时(@Inject(APP_CONFIG)私有配置){}这里有一个提到:http://blog.thoughtram.io/angular/2016/05/23/opaque-tokens-in-angular -2.html但不是为什么. (3认同)
  • 将步骤1中的代码放入`environment.ts`和`environment.prod.ts`是否有意义,以便每个环境可以有不同的常量?@IlyaChernomordik在他的答案的最后一段开始提到这一点. (2认同)

pix*_*its 63

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

provide(token: any, {useClass, useValue, useExisting, useFactory, deps, multi}
Run Code Online (Sandbox Code Playgroud)

与Angular 1相比

app.service在Angular1中等效useClass于Angular2.

app.factory在Angular1中等效useFactory于Angular2.

app.constant并且app.value已经简化为useValue具有较少约束.即没有config阻挡了.

app.provider - Angular 2中没有等效词.

例子

要使用根注入器进行设置:

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

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

providers: [provide(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})]
Run Code Online (Sandbox Code Playgroud)

provide 简而言之:

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

使用注射器,获取值很容易:

var endpoint = injectorValue.get(API_ENDPOINT);
Run Code Online (Sandbox Code Playgroud)

  • 对不起,我不明白我是怎么把它注入我的服务的?由于我正在使用外部文件,是否需要将其导出? (5认同)
  • 我实际上想在外部文件中设置我的设置,例如:settings.ts这个文件怎么样? (2认同)

Nac*_*cho 56

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

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

例如

export const environment = {
  production: false,
  apiUrl: 'http://localhost:8000/api/'
};
Run Code Online (Sandbox Code Playgroud)

然后是你的服务:

import { environment } from '../../environments/environment';
...
environment.apiUrl;
Run Code Online (Sandbox Code Playgroud)


Anj*_*... 45

更新了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' ],
    };
    
    Run Code Online (Sandbox Code Playgroud)
  • environment.qa.ts

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

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

应用程序中的用例

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

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

getHostURL(): string {
    return environment.apiHost;
  }
Run Code Online (Sandbox Code Playgroud)

构建中的用例

打开你的角度cli文件.angular-cli.json并在里面"apps": [{...}]添加以下代码

 "apps":[{
        "environments": {
            "dev": "environments/environment.ts",
            "prod": "environments/environment.prod.ts",
            "qa": "environments/environment.qa.ts",
           }
         }
       ]
Run Code Online (Sandbox Code Playgroud)

如果你想建立生产,运行 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'
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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)
  }
 }
Run Code Online (Sandbox Code Playgroud)

  • 这不像Constant那样工作.常数的值始终相同.在您的情况下,您的`API_ENDPOINT`值可以在任何时间点覆盖.如果``.ConstantService.API_ENDPOINT ='blah blah'`在从`constant-service`导入所谓的"常量"后随时在类中声明,API_ENDPOINT的新值将是''blah blah'`.您的解决方案仅显示如何使用服务访问变量,而不是使用常量. (5认同)
  • @Devner 只是让它们只读 `readonly API_ENDPOINT :String;` (2认同)

Mor*_*avi 30

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

我们需要能够将这个api端点注入到我们的服务中(考虑将服务注入到另一个服务中).我们也不需要为此创建一个完整的类,我们要做的就是在我们的ApiEndpoint服务中注入一个字符串.要通过pixelbits完成出色的答案,下面是完整的代码,了解如何在Angular 2中完成:

首先,我们需要告诉角度如何提供,当我们在我们的应用程序(认为它作为注册依赖)提出要求我们ApiEndpoint的实例:

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


然后在服务中我们这个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...
}
Run Code Online (Sandbox Code Playgroud)


Jav*_*tes 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;

}
Run Code Online (Sandbox Code Playgroud)

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' );
Run Code Online (Sandbox Code Playgroud)

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 {}
Run Code Online (Sandbox Code Playgroud)

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@

  }
Run Code Online (Sandbox Code Playgroud)

结果是干净的,并且对于John Papa在本期中的最新评论感谢控制台上没有任何警告:

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

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


Ale*_*idt 17

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

app.const.ts

'use strict';

export const dist = '../path/to/dist/';
Run Code Online (Sandbox Code Playgroud)

app.service.ts

import * as AppConst from '../app.const'; 

@Injectable()
export class AppService {

    constructor (
    ) {
        console.log('dist path', AppConst.dist );
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,你使用的服务范围之外的变量,所以你也可以使用窗口全局变量.我们要做的是将常量引入Angular4依赖注入系统,这样我们就可以保持范围干净,可存根或可模拟. (2认同)

Sna*_*ops 9

只需使用Typescript常量

export var API_ENDPOINT = 'http://127.0.0.1:6666/api/';
Run Code Online (Sandbox Code Playgroud)

您可以在依赖注入器中使用它

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

  • 为什么不const? (4认同)

occ*_*asl 5

如果您使用的是我推荐的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)
      }),
Run Code Online (Sandbox Code Playgroud)

自定义类型.d.ts

declare var API_URL: string;
declare var JWT_TOKEN_NAME: string;
interface GlobalEnvironment {
  API_URL: string;
  JWT_TOKEN_NAME: string;
}
Run Code Online (Sandbox Code Playgroud)

成分

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


Jua*_*dán 5

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 {
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的服务中:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)