回答:
以下の変更点は、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チーム自体が提供する構成の解決策は、こちらにあります。
ここにすべての関連コードがあります:
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
}
}
これで、文字列名を使用せず、静的チェックのためのインターフェースを使用して、どこにでも構成を挿入できます。
もちろん、インターフェースと定数をさらに分離して、生産と開発で異なる値を提供できるようにすることができます。
environment.ts
とenvironment.prod.ts
あなたは環境ごとに異なる定数を持つことができるように?@IlyaChernomordikは彼の回答の最後の段落でこれについて言及し始めました。
Angular2では、次のように定義を定義することで、さまざまな種類の依存関係をセットアップできます。
provide(token: any, {useClass, useValue, useExisting, useFactory, deps, multi}
Angular 1と比較する
app.service
Angular1の場合はAngular2の場合と同じuseClass
です。
app.factory
Angular1では useFactory
です。
app.constant
とapp.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 4では、環境クラスを使用してすべてのグローバルを保持できます。
デフォルトでは、environment.tsとenvironment.prod.tsがあります。
例えば
export const environment = {
production: false,
apiUrl: 'http://localhost:8000/api/'
};
そしてあなたのサービスで:
import { environment } from '../../environments/environment';
...
environment.apiUrl;
const
サービスの内部にアクセスしようとしている場合は、アプリモジュールのプロバイダー配列にサービスを「提供」する必要がある場合があります{ provide: 'ConstName', useValue: ConstName }
。これなしで実行時エラーが発生しました。
これで、プロジェクトが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
あなたのためにそれを行うことができ、同じようにqa
かdev
私は私のプロバイダーで以下のようなことをしています:
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)
}
}
API_ENDPOINT
値はいつでも上書きすることができます。場合はthis.ConstantService.API_ENDPOINT = 'blah blah'
、あなたのいわゆる「定数」の後にクラスいつに宣言されてからインポートされconstant-service
、API_ENDPOINTの新しい値は次のようになります'blah blah'
。ソリューションは、定数を使用するのではなく、サービスを使用して変数にアクセスする方法を示しています。
readonly API_ENDPOINT :String;
ng build --env=prod
ApiEndpointとして文字列定数を含むAppSettingsクラスを使用するアプローチは機能しますが、単体テスト時にこの実際のApiEndpointを他のいくつかの値と交換できないため、理想的ではありません。
このAPIエンドポイントをサービスに挿入できる必要があります(サービスを別のサービスに挿入することを考えてください)。また、このためにクラス全体を作成する必要はありません。ApiEndpointであるサービスに文字列を挿入するだけです。pixelbitsによる優れた回答を完了するために、Angular 2でどのように実行できるかに関する完全なコードを次に示します。
まず、アプリでApiEndpointのインスタンスを要求するときに、Angularにインスタンスを提供する方法を指示する必要があります(依存関係の登録と考えてください)。
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide('ApiEndpoint', {useValue: 'http://127.0.0.1:6666/api/'})
]);
そしてサービスで、我々は注入サービスコンストラクタにこのApiEndpointを、角は上記の当社の登録に基づいて、私たちのためにそれを提供します:
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...
}
これは、このシナリオでの最近の経験です。
私は公式および更新されたドキュメントをここでフォローしました:
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
キーは、インターフェイスの別のファイルに実装されていました。
すべてのソリューションは複雑なようです。この場合の最も簡単な解決策を探しており、定数を使用したいだけです。定数は単純です。次の解決策に反することはありますか?
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 );
}
}
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/'}), ...]);
const
yest
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)});
}
ビルド中に生成されたプロパティファイルの使用は、簡単です。これは、Angular CLIが使用するアプローチです。各環境のプロパティファイルを定義し、ビルド中にコマンドを使用して、アプリにコピーするファイルを決定します。次に、使用するプロパティファイルをインポートします。
https://github.com/angular/angular-cli#build-targets-and-environment-files
Angular4の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);
}
}
グローバル定数を定義する別の方法があります。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ファイルの値を簡単に変更できます。私はこの方法を常にエラー/警告メッセージに使用します。
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エンドポイントが特定の状況で変更されるのは妥当です。
しかし、その場合、constant
関数への単一のURLの文字列リテラル表現として提供しても機能しませんでした。
AngularJS $provide.constant
関数が導入されたとき、JavaScriptには標準モジュールの概念がなかったというのが、より良い議論であり、AngularJS 関数が存在する理由とより整合している可能性があります。その場合、グローバルは値を共有するために使用され、可変または不変であり、グローバルの使用には問題があります。
そうは言っても、フレームワークを通じてこのようなものを提供すると、そのフレームワークへの結合が増加します。また、Angular固有のロジックと他のシステムで機能するロジックを組み合わせます。
これは、それが間違っているまたは有害なアプローチであると言っているわけではありませんが、個人的には、Angular 2アプリケーションで定数が必要な場合は、
export const π = 3.14159265;
AngularJSを使用していたのと同じように。
変化するほど...
Angular 2でアプリケーション全体の定数を作成する最良の方法は、environment.tsファイルを使用することです。このような定数を宣言する利点は、環境ごとに異なる環境ファイルが存在する可能性があるため、環境に応じて定数を変更できることです。
グローバル変数のクラスを作成し、このクラスを次のようにエクスポートできます。
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);
}
}
これは、constructor
またはngOnInit(){}
、または任意の事前定義メソッドで使用できます。
AppSettings
クラスは抽象的で、API_ENDPOINT
メンバーはである必要がありますreadonly
。