web-dev-qa-db-de.com

Definieren Sie globale Konstanten in Winkel 2

In Angular 1.x können Sie Konstanten wie folgt definieren:

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

Was wäre das Äquivalent in Angular2 (mit TypeScript)? Ich möchte einfach nicht die API-Basis-URL in allen meinen Services immer und immer wieder wiederholen.

206
AndreFeijo

Die folgenden Änderungen funktionieren für mich an der Endversion von Angular 2:

export class AppSettings {
   public static API_ENDPOINT='http://127.0.0.1:6666/api/';
}

Und dann im Dienst:

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

Die Lösung für die Konfiguration, die das Winkelteam selbst zur Verfügung stellt, ist hier .

Hier ist der relevante Code:

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) Ihre.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
    }   
}

Jetzt können Sie die Konfiguration überall einfügen, ohne die String-Namen zu verwenden und Ihre Schnittstelle für statische Prüfungen zu verwenden.

Sie können natürlich die Schnittstelle und die Konstante weiter voneinander trennen, um unterschiedliche Werte in Produktion und Entwicklung angeben zu können, z.

146

In Angular2 haben Sie die folgende Definition von deploy , mit der Sie verschiedene Arten von Abhängigkeiten einrichten können:

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

Vergleich mit Winkel 1

app.service in Angular1 entspricht useClass in Angular2.

app.factory in Angular1 entspricht useFactory in Angular2.

app.constant und app.value wurde mit weniger Einschränkungen zu useValue vereinfacht. es gibt keinen config-Block mehr.

app.provider - In Angular 2 gibt es keine Entsprechung.

Beispiele

Einrichten mit dem Wurzelinjektor:

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

Oder mit dem Injektor Ihrer Komponente einrichten:

providers: [provide(API_ENDPOINT, { useValue: 'http://127.0.0.1:6666/api/'})]

provide ist eine kurze Hand für:

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

Mit dem Injektor ist der Wert einfach zu ermitteln:

var endpoint = injectorValue.get(API_ENDPOINT);
61
pixelbits

In Angular 4 können Sie die Umgebungsklasse verwenden, um alle Ihre globalen Werte zu erhalten.

Sie verfügen standardmäßig über environment.ts und environment.prod.ts.

Zum Beispiel

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

Und dann zu Ihren Diensten:

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

Aktualisiert für Angular 4+

Jetzt können wir einfach eine Umgebungsdatei verwenden, die den Winkel als Standard bereitstellt, wenn Ihr Projekt über das Winkel-Cli erstellt wird.

zum Beispiel 

Erstellen Sie in Ihrem Umgebungsordner folgende Dateien 

  • environment.prod.ts
  • environment.qa.ts
  • environment.dev.ts

und jede Datei kann verwandte Codeänderungen enthalten, z.

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

Anwendungsfall in der Anwendung

Sie können Umgebungen in jede Datei importieren, z. B. Dienste clientUtilServices.ts

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

getHostURL(): string {
    return environment.apiHost;
  }

Anwendungsfall in Build

Öffnen Sie Ihre eckige CLI-Datei .angular-cli.json und fügen Sie in "apps": [{...}] folgenden Code hinzu 

 "apps":[{
        "environments": {
            "dev": "environments/environment.ts",
            "prod": "environments/environment.prod.ts",
            "qa": "environments/environment.qa.ts",
           }
         }
       ]

Wenn Sie für die Produktion erstellen möchten, führen Sie ng build --env=prod aus. Die Konfiguration wird von environment.prod.ts gelesen. Auf dieselbe Weise wie für qa oder dev.

## Ältere Antwort

Ich habe etwas in meinem Provider gemacht:

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

Dann habe ich überall Zugriff auf alle Constant-Daten 

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

Während der Ansatz mit einer AppSettings-Klasse mit einer Zeichenfolgenkonstante als ApiEndpoint funktioniert, ist er nicht ideal, da wir diesen echten ApiEndpoint zum Zeitpunkt des Unit-Tests nicht gegen andere Werte austauschen könnten.

Wir müssen in der Lage sein, diese API-Endpunkte in unsere Services zu integrieren (denken Sie daran, einen Service in einen anderen Service zu integrieren). Wir müssen dafür auch keine ganze Klasse erstellen. Wir möchten lediglich einen String in unsere Services einfügen, der unser ApiEndpoint ist. Um die ausgezeichnete Antwort von Pixelbits zu vervollständigen, hier der vollständige Code, wie es in Angular 2 gemacht werden kann:

Zuerst müssen wir Angular wie eine Instanz unseres ApiEndpoint zur Verfügung stellen , wenn wir in unserer App danach fragen ( Stellen Sie sich vor, Sie registrieren eine Abhängigkeit):

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


Und dann fügen wir in den Dienst diesen ApiEndpoint in den Dienstkonstruktor ein und Angular) wird ihn bereitstellen für uns aufgrund unserer Anmeldung oben:

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

Dies ist meine jüngste Erfahrung mit diesem Szenario:

  • @ angle/cli: 1.0.0
  • node: 6.10.2
  • @ eckig/Kern: 4.0.0

Ich habe die offiziellen und aktualisierten Dokumente hier verfolgt:

https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#dependency-injection-tokens

Es scheint, dass OpaqueToken jetzt veraltet ist und wir InjectionToken verwenden müssen. Dies sind also meine Dateien, die wie ein Zauber laufen:

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: '[email protected][email protected]'

};

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:  [email protected][email protected]

  }

Das Ergebnis ist sauber und es gibt keine Warnungen auf der Konsole. Danke an den letzten Kommentar von John Papa in dieser Ausgabe:

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

Der Schlüssel wurde in einer anderen Datei der Schnittstelle implementiert.

28
JavierFuentes

Alle Lösungen scheinen kompliziert zu sein. Ich suche die einfachste Lösung für diesen Fall und möchte nur Konstanten verwenden. Konstanten sind einfach. Gibt es etwas, was gegen die folgende Lösung spricht?

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

}
13

Verwenden Sie einfach eine TypeScript-Konstante

export var API_ENDPOINT = 'http://127.0.0.1:6666/api/';

Sie können es im Abhängigkeitsinjektor verwenden

bootstrap(AppComponent, [provide(API_ENDPOINT, {useValue: 'http://127.0.0.1:6666/api/'}), ...]);
7
SnareChops

Wenn Sie Webpack verwenden, was ich empfehle, können Sie Konstanten für verschiedene Umgebungen einrichten. Dies ist besonders nützlich, wenn Sie auf Umgebungsebene unterschiedliche konstante Werte haben.

In Ihrem /config-Verzeichnis befinden sich wahrscheinlich mehrere Webpack-Dateien (z. B. webpack.dev.js, webpack.prod.js usw.). Dann haben Sie einen custom-typings.d.ts, den Sie dort hinzufügen. Hier ist das allgemeine Muster, das in jeder Datei zu befolgen ist, und ein Beispiel für eine Verwendung in einer Komponente.

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

Komponente

export class HomeComponent implements OnInit {
  api_url:string = API_URL;
  authToken: string = "Bearer " + localStorage.getItem(JWT_TOKEN_NAME)});
}
4
occasl

Ein Ansatz für Angular4 wäre die Definition einer Konstante auf Modulebene:

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

Dann in Ihrem Dienst:

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

Die Verwendung einer Eigenschaftendatei, die während eines Builds generiert wird, ist einfach und problemlos. Dies ist der Ansatz, den die Angular CLI verwendet. Definieren Sie eine Eigenschaftendatei für jede Umgebung und verwenden Sie während des Builds einen Befehl, um zu bestimmen, welche Datei in Ihre App kopiert wird. Dann importieren Sie einfach die zu verwendende Eigenschaftendatei.

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

2
R.Creager

Der module.constant von AngularJS definiert keine Konstante im Standard Sinne.

Obwohl es als Anbieterregistrierungsmechanismus für sich allein steht, wird es am besten im Zusammenhang mit der zugehörigen module.value ($provide.value) -Funktion verstanden. In den offiziellen Unterlagen wird der Anwendungsfall eindeutig angegeben:

Registrieren Sie einen Wertedienst mit dem $ injector, z. B. eine Zeichenfolge, eine Zahl, ein Array, ein Objekt oder eine Funktion. Dies ist eine Abkürzung für die Registrierung eines Dienstes, bei dem die $ get -Eigenschaft seines Providers eine Factory-Funktion ist, die keine Argumente akzeptiert und den Wertedienst zurückgibt. Das bedeutet auch, dass es nicht möglich ist, andere Services in einen Value-Service einzubinden.

Vergleichen Sie dies mit der Dokumentation für module.constant ($provide.constant), die auch den Anwendungsfall (Hervorhebungsmine) eindeutig angibt:

Registrieren Sie einen konstanten Dienst mit dem $ injector, z. B. eine Zeichenfolge, eine Zahl, ein Array, ein Objekt oder eine Funktion. Wie der Wert ist es nicht möglich, andere Services in eine Konstante zu injizieren . Im Gegensatz zu value kann jedoch eine a-Konstante in eine Modulkonfigurationsfunktion eingefügt werden (siehe angle.Module) und nicht durch einen AngularJS-Dekorator überschrieben werden.

Daher liefert die AngularJS constant-Funktion keine Konstante in der allgemein verständlichen Bedeutung des Begriffs im Feld.

Die Einschränkungen, die dem bereitgestellten Objekt auferlegt werden, und seine frühere Verfügbarkeit über den $ injector legen eindeutig nahe, dass der Name analog verwendet wird.

Wenn Sie eine tatsächliche Konstante in einer AngularJS-Anwendung haben möchten, würden Sie dieselbe wie in einem beliebigen JavaScript-Programm "angeben"

export const π = 3.14159265;

In Winkel 2 ist dieselbe Technik anwendbar.

Angular 2-Anwendungen haben keine Konfigurationsphase im selben Sinne wie AngularJS-Anwendungen. Darüber hinaus gibt es keinen Service-Dekorationsmechanismus ( AngularJS Decorator ). Dies ist jedoch nicht besonders überraschend, da sie sich voneinander unterscheiden.

Das Beispiel von

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

ist vage willkürlich und etwas abschreckend, weil $provide.constant verwendet wird, um ein Objekt anzugeben, das nebenbei auch eine Konstante ist. Sie hätten genauso gut schreiben können

export const apiEndpoint = 'http://127.0.0.1:6666/api/';

für alle kann sich entweder ändern.

Jetzt wird das Argument für die Testbarkeit, die die Konstante verspottet, gemindert, weil es sich buchstäblich nicht ändert.

Man spottet nicht π.

Natürlich kann es bei Ihrer anwendungsspezifischen Semantik sein, dass sich Ihr Endpunkt ändern könnte oder Ihre API über einen nicht transparenten Failover-Mechanismus verfügt. Daher ist es sinnvoll, dass sich der API-Endpunkt unter bestimmten Umständen ändert.

In diesem Fall hätte es jedoch nicht funktioniert, es als String-Literal-Darstellung einer einzelnen URL für die constant-Funktion bereitzustellen.

Ein besseres Argument und wahrscheinlich ein weiteres Argument, das mit dem Grund für die Existenz der Funktion AngularJS $provide.constant übereinstimmt, ist, dass JavaScript bei der Einführung von AngularJS kein standard - Modulkonzept hatte. In diesem Fall würden Globals verwendet, um Werte zu teilen, veränderbar oder unveränderlich, und die Verwendung von Globals ist problematisch.

Die Bereitstellung eines solchen Rahmens durch ein Framework erhöht jedoch die Kopplung mit diesem Framework. Es mischt auch die Angular-spezifische Logik mit einer Logik, die in jedem anderen System funktionieren würde.

Dies bedeutet nicht, dass dies eine falsche oder schädliche Vorgehensweise ist, aber wenn ich eine -Konstante in einer Angular 2-Anwendung haben möchte, schreibe ich

export const π = 3.14159265;

genau wie ich hätte ich AngularJS benutzt.

Je mehr sich die Dinge ändern ...

0
Aluan Haddad

Ich habe eine andere Möglichkeit, globale Konstanten zu definieren. Denn wenn wir in ts-Datei definiert haben, ist es im Build-Modus nicht einfach, Konstanten zu finden, die den Wert ändern.

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

Im App-Ordner füge ich den Ordner configs/setting.json hinzu

Inhalt in setting.json

{
    "baseUrl": "http://localhost:52555"
}

Fügen Sie im App-Modul APP_INITIALIZER hinzu

   {
      provide: APP_INITIALIZER,
      useFactory: (setting: SettingService) => function() {return setting.getSetting()},
      deps: [SettingService],
      multi: true
    }

auf diese Weise kann ich den Wert in der Json-Datei einfacher ändern. __ Ich verwende diesen Weg auch für ständige Fehler-/Warnmeldungen.

0
Hien Nguyen

Anwendungskonstanten können in Angular 2 am besten mithilfe von environment.ts-Dateien erstellt werden. Der Vorteil der Deklaration solcher Konstanten besteht darin, dass Sie sie je nach Umgebung variieren können, da für jede Umgebung eine andere Umgebungsdatei vorhanden ist.

0
Hassan Arafat