web-dev-qa-db-ja.com

でグローバル定数を定義する Angular 2

Angular 1.xでは、次のように定数を定義できます。

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

(TypeScriptを使った)Angular 2の同等物は何でしょうか。私はすべての私のサービスで何度も何度も何度もAPIベースURLを繰り返したくない。

214
AndreFeijo

以下の変更は私に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);
    }
}
224
AndreFeijo

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

これで、文字列名を使わずに、そして静的チェックのためにあなたのインターフェースを使って、どこにでもconfigを注入することができます。

生産と開発で異なる値を提供できるように、もちろんインターフェースと定数をさらに分離することができます。

149

Angular 2では、次の provide 定義があります。これにより、さまざまな種類の依存関係を設定できます。

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

Angular 1との比較

Angular 1のapp.serviceは、Angular 2のuseClassと同じです。

Angular 1のapp.factoryは、Angular 2の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);
62
pixelbits

Angular 4では、環境クラスを使用してすべてのグローバルを保持できます。

デフォルトではenvironment.tsとenvironment.prod.tsがあります。

例えば

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

そして、あなたのサービスに:

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

Angular 4+用に更新

あなたのプロジェクトがangular-cliを介して生成されている場合、今度は、単に角度をデフォルトとして提供する環境ファイルを使用することができます。

例えば

ご使用の環境フォルダーに以下のファイルを作成します。

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

アプリケーションでのユースケース

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",
           }
         }
       ]

プロダクション用にビルドしたい場合は、qaまたはdevに対して行うことができるのと同じ方法でng build --env=prodを実行し、environment.prod.tsから構成を読み取ります。

##古い答え

私のプロバイダでは、以下のようなことをしています。

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)
  }
 }
37
Anjum....

ApiEndpointとして文字列定数を持つAppSettingsクラスを使用するアプローチは機能しますが、単体テスト時にこの実際のApiEndpointを他の値と交換できないため、理想的ではありません。

このAPIエンドポイントをサービスに注入できる必要があります(サービスを別のサービスに注入することを考えてください)。また、このためにクラス全体を作成する必要もありません。ApiEndpointであるサービスに文字列を挿入するだけです。 excellent answer bypixelbits を完成させるために、Angular 2:

最初に、アプリで要求したときにApiEndpointのインスタンスをprovideする方法をAngularに伝える必要があります(考えてみてください)依存関係の登録として):

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


そして、サービスでinjectこの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...
}
30
Morteza Manavi

これが私のこのシナリオに関する最近の経験です。

  • @ angle/cli:1.0.0
  • ノード:6.10.2
  • @ angle/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

キーは、異なるファイルのインターフェースに実装されていました。

28
JavierFuentes

すべての解決策は複雑そうです。私はこのケースのための最も簡単な解決策を探しています、そして私はただ定数を使いたいです。定数は単純です。次の解決策に反対するものはありますか?

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

}
14

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/'}), ...]);
7
SnareChops

Webpack を使用しているのであれば、私はお勧めですが、さまざまな環境に合わせて定数を設定できます。環境ごとに異なる定数値がある場合、これは特に有益です。

/configディレクトリの下に複数のwebpackファイルがある可能性があります(例:webpack.dev.js、webpack.prod.jsなど)。それからそれらを追加するcustom-typings.d.tsがあります。これが各ファイルで従う一般的なパターンとComponentの使用例です。

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

Angular 4の1つの方法は、モジュールレベルで定数を定義することです。

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);
    }
}
3
Juangui Jordán

ビルド中に生成されたプロパティファイルを使用するのは簡単で簡単です。これがAngular CLIが使用するアプローチです。環境ごとにプロパティファイルを定義し、ビルド中にコマンドを使用してどのファイルがアプリにコピーされるかを決定します。その後、使用するプロパティファイルをインポートするだけです。

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

2
R.Creager

AngularJSのmodule.constantは標準的な意味で定数を定義していません。

プロバイダ登録メカニズムとしては自立していますが、関連するmodule.value$provide.value)関数の文脈で最もよく理解されます。公式文書にユースケースが明確に記載されています。

文字列、数値、配列、オブジェクト、関数などの値サービスを$ injectorに登録します。これは、プロバイダの$ getプロパティが引数を取らずに値serviceを返すファクトリ関数であるサービスを登録するための略語です。それはまた、他のサービスを価値サービスに注入することが不可能であることを意味します。

これをmodule.constant$provide.constant)のドキュメントと比較してみてください。これもまたユースケースを明確に述べています(強調)。

文字列、数値、配列、オブジェクト、関数などの定数サービスを$ injectorに登録します。値のように、他のサービスを定数に注入することは不可能です。しかし、値とは異なり、 定数をモジュール構成関数に挿入することができ(Angular.Moduleを参照)、AngularJSデコレータでオーバーライドすることはできません

したがって、AngularJSのconstant関数は、この分野の用語の一般的に理解されている意味で定数を提供しません。

そうは言っても、提供されたオブジェクトに課された制限は、$インジェクタによるその以前の可用性と共に、名前がアナロジーによって使用されていることを明らかに示唆しています。

AngularJSアプリケーションで実際の定数が必要な場合は、JavaScriptプログラムで使用するのと同じ方法で「提供」します。

export const π = 3.14159265;

Angular 2では、同じ手法が適用できます。

Angular 2アプリケーションにはAngular JSアプリケーションと同じ意味で設定フェーズはありません。さらに、サービスデコレータメカニズム( 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エンドポイントを変更するのが妥当です。

しかしその場合、constant関数への単一のURLの文字列リテラル表現としてそれを提供することはうまくいきませんでした。

より良い議論、そしておそらくAngularJSの$provide.constant関数が存在する理由と一致した議論は、AngularJSが導入されたときにはJavaScriptに standard moduleの概念がなかったということです。その場合、グローバルは可変または不変の値を共有するために使用され、グローバルの使用は問題があります。

それにもかかわらず、フレームワークを通してこのようなものを提供することは、そのフレームワークへのカップリングを増やします。また、Angular特定のロジックと他のシステムで機能するロジックを組み合わせています。

これが間違った、あるいは有害なアプローチであると言っているわけではありませんが、個人的には、Angular 2アプリケーションで constant が欲しい場合は、

export const π = 3.14159265;

angularJSを使用していたのと同じように。

より多くのことが変わります...

0
Aluan Haddad

グローバル定数を定義する別の方法があります。なぜなら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ファイルの値を簡単に変更できます。私はこの方法を絶えずエラー/警告メッセージにも使っています。

0
Hien Nguyen

Angular 2でアプリケーション全体の定数を作成する最善の方法は、environment.tsファイルを使用することです。このような定数を宣言する利点は、環境ごとに異なる環境ファイルが存在する可能性があるため、環境に応じてそれらを変更できることです。

0
Hassan Arafat