typescript - Küresel sabitleri tanımla
Angular 1.x'te sabitleri bu şekilde tanımlayabilirsiniz:
angular.module('mainApp.config', [])
.constant('API_ENDPOINT', 'http://127.0.0.1:6666/api/')
Angular'da (TypeScript ile) karşılığı ne olurdu?
Sadece tüm servislerimde API temel URL'ini sürekli tekrar etmek istemiyorum.
Cevap #1
Aşağıdaki değişiklikler Angular 2 son sürümünde benim için çalışıyor:
export class AppSettings {
public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}
Ve sonra hizmette:
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);
}
}
Cevap #2
Angular ekibi tarafından sağlanan yapılandırma çözümü burada bulunabilir.
İşte tüm ilgili kod:
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
}
}
Artık yapılandırmayı her yerde, string isimlerini kullanmadan ve statik kontroller için arayüzünüzü kullanarak enjekte edebilirsiniz.
Elbette, üretim ve geliştirme ortamlarında farklı değerler sağlayabilmek için Arayüz ve sabiti daha da ayırabilirsiniz, örneğin.
Cevap #3
Angular 4+ için güncellendi
Şimdi, projeniz angular-cli ile oluşturulduysa Angular'ın varsayılan olarak sağladığı ortam dosyalarını basitçe kullanabiliriz.
örneğin
Ortamlar klasörünüzde aşağıdaki dosyaları oluşturun
environment.prod.tsenvironment.qa.tsenvironment.dev.ts
ve her dosya şunlar gibi ilgili kod değişikliklerini içerebilir:
environment.prod.tsexport const environment = { production: true, apiHost: 'https://api.somedomain.com/prod/v1/', CONSUMER_KEY: 'someReallyStupidTextWhichWeHumansCantRead', codes: [ 'AB', 'AC', 'XYZ' ], };environment.qa.tsexport const environment = { production: false, apiHost: 'https://api.somedomain.com/qa/v1/', CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead', codes: [ 'AB', 'AC', 'XYZ' ], };environment.dev.tsexport const environment = { production: false, apiHost: 'https://api.somedomain.com/dev/v1/', CONSUMER_KEY : 'someReallyStupidTextWhichWeHumansCantRead', codes: [ 'AB', 'AC', 'XYZ' ], };
Uygulamadaki kullanım durumu
Ortamları, clientUtilServices.ts gibi herhangi bir dosyaya içe aktarabilirsiniz
import {environment} from '../../environments/environment';getHostURL(): string {
return environment.apiHost;
}
Yapımda kullanım durumu
Angular CLI dosyanızı .angular-cli.json açın ve "apps": [{...}] içinin içine aşağıdaki kodu ekleyin
"apps":[{
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts",
"qa": "environments/environment.qa.ts",
}
}
]
Eğer üretim için derleme yapmak istiyorsanız, ng build --env=prod komutunu çalıştırın; bu, environment.prod.ts dosyasından yapılandırmayı okuyacaktır. Aynı şekilde bunu qa veya dev için de yapabilirsiniz.
## Eski cevap
Sağlayıcımda aşağıdakine benzer bir şey yapıyordum:
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'
}
}
O zaman her yerde tüm Sabit verilere erişimim var
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)
}
}
Cevap #4
Angular2'de, farklı türde bağımlılıkları ayarlamanıza olanak tanıyan aşağıdaki provide tanımına sahipsiniz:
provide(token: any, {useClass, useValue, useExisting, useFactory, deps, multi}
Angular 1 ile karşılaştırıldığında
Angular1'de app.service, Angular2'de useClass'a eşdeğerdir.
Angular1'deki app.factory, Angular2'deki useFactory'ye eşdeğerdir.
app.constant ve app.value, daha az kısıtlama ile useValue olarak basitleştirildi. Yani artık config bloğu yok.
app.provider - Angular 2'de eşdeğeri yok.
Örnekler
Kök enjektör ile kurmak için:
bootstrap(AppComponent,[provide(API_ENDPOINT, { useValue='http://127.0.0.1:6666/api/' })]);
Veya bileşeninizin enjektörü ile ayarlayın:
providers: [provide(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})]
provide, şunun kısaltmasıdır:
var injectorValue = Injector.resolveAndCreate([
new Provider(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})
]);
Enjektör ile değeri almak kolaydır:
var endpoint = injectorValue.get(API_ENDPOINT);
Cevap #5
Angular 4'te, tüm genel değişkenlerinizi saklamak için environment sınıfını kullanabilirsiniz.
Varsayılan olarak environment.ts ve environment.prod.ts dosyalarınız vardır.
Örneğin
export const environment = {
production: false,
apiUrl: 'http://localhost:8000/api/'
};
Ve sonra hizmetin üzerinde:
import { environment } from '../../environments/environment';
...
environment.apiUrl;
Cevap #6
Bir string sabit olarak ApiEndpoint içeren bir AppSettings sınıfına sahip yaklaşım işe yarasa da, bu ideal değildir çünkü birim testi sırasında bu gerçek ApiEndpoint'i başka değerlerle değiştiremeyiz.
Bu API uç noktalarını servislerimize enjekte edebilmemiz gerekiyor (bir servisi başka bir servise enjekte etmeyi düşünün). Ayrıca bunun için tamamen bir sınıf oluşturmamıza da gerek yok, yapmamız gereken tek şey bir dizeyi, yani ApiEndpoint'imiz olan dizeyi servislerimize enjekte etmek. pixelbits tarafından verilen mükemmel cevabı tamamlamak için, işte bunun Angular 2'de nasıl yapılabileceğini gösteren tam kod:
Öncelikle Angular'a uygulamamızda istediğimizde ApiEndpoint'imizin bir örneğini nasıl sağlayacağını söylememiz gerekiyor (bunu bir bağımlılığı kaydetmek olarak düşünebilirsiniz):
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide('ApiEndpoint', {useValue: 'http://127.0.0.1:6666/api/'})
]);
Ve sonra serviste, bu ApiEndpoint'i servis yapıcısına enjekte ediyoruz ve Angular, yukarıdaki kaydımıza göre bunu bizim için sağlayacak:
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...
}
Cevap #7
Bu senaryoyla ilgili son deneyimim şunlardır:
- @angular/cli: 1.0.0
- node: 6.10.2
- @angular/core: 4.0.0
Resmi ve güncellenmiş dokümanları burada takip ettim:
https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#dependency-injection-tokens
Görünüşe göre OpaqueToken artık kullanımdan kaldırıldı ve InjectionToken kullanmamız gerekiyor, bu yüzden dosyalarım sorunsuz çalışıyor:
app-config.arayüzü.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@
}
Sonuç temiz ve konsolda uyarı yok, bu sorundaki John Papa'nın son yorumu sayesinde:
https://github.com/angular/angular-cli/issues/2034
Anahtar, arayüzü farklı bir dosyada uygulamaktı.
Cevap #8
Tüm çözümler karmaşık görünüyor. Bu durum için en basit çözümü arıyorum ve sadece sabitleri kullanmak istiyorum. Sabitler basittir. Aşağıdaki çözüme karşı konuşan bir şey var mı?
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 );
}
}
Cevap #9
Sadece bir Typescript sabiti kullan
export var API_ENDPOINT = 'http://127.0.0.1:6666/api/';
Bunu bağımlılık enjeksiyonunda kullanabilirsiniz
bootstrap(AppComponent, [provide(API_ENDPOINT, {useValue: 'http://127.0.0.1:6666/api/'}), ...]);
