답변:
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) 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}
각도 1과 비교
app.service
Angular1의 경우 Angular2의 경우와 같습니다 useClass
.
app.factory
Angular1의 경우 Angular2의 경우와 같습니다 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를 서비스 생성자에 주입 하고 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...
}
이것은이 시나리오에 대한 최근의 경험입니다.
나는 공식 및 업데이트 된 문서를 따라왔다.
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)
}),
맞춤 타이핑 .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에 대한 한 가지 접근 방식은 모듈 수준에서 상수를 정의하는 것입니다.
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
함수가 존재하는 이유와 더 나은 논쟁은 아마도 AngularJS가 도입되었을 때 JavaScript에는 표준 모듈 개념 이 없다는 것 입니다. 이 경우 전역은 변경 가능하거나 불변의 값을 공유하는 데 사용되며 전역 사용은 문제가됩니다.
즉, 프레임 워크를 통해 이와 같은 것을 제공하면 해당 프레임 워크와의 연결이 증가합니다. 또한 Angular 특정 로직을 다른 시스템에서 작동하는 로직과 혼합합니다.
이것은 잘못되었거나 유해한 접근 방법이라고 말하는 것이 아니라 개인적 으로 Angular 2 응용 프로그램에서 상수 를 원한다면
export const π = 3.14159265;
내가 AngularJS를 사용했던 것처럼.
더 많은 것들이 바뀐다 ...
전역 변수에 대한 클래스를 만든 다음이 클래스를 다음과 같이 내보낼 수 있습니다.
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
.