variable globales define declarar constantes typescript angular

define - constantes globales en typescript



Definir constantes globales (16)

En Angular 1.x puede definir constantes como esta:

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

¿Cuál sería el equivalente en Angular2 (con TypeScript)?

Simplemente no quiero repetir la URL base de API una y otra vez en todos mis servicios.


Actualizado para Angular 4+

Ahora podemos simplemente usar el archivo de entornos que angular proporciona valor predeterminado si su proyecto se genera a través de angular-cli.

por ejemplo

En su carpeta de entornos, cree los siguientes archivos

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

y cada archivo puede contener cambios de código relacionados como:

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

Caso de uso en la aplicación

Puede importar entornos en cualquier archivo, como servicios clientUtilServices.ts

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

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

Caso de uso en construcción

Abra su archivo .angular-cli.json angular .angular-cli.json y dentro de "apps": [{...}] agregue el siguiente código

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

Si desea compilar para producción, ejecute ng build --env=prod , leerá la configuración de environment.prod.ts , de la misma manera que puede hacerlo para qa o dev

## Respuesta anterior

He estado haciendo algo como a continuación, en mi proveedor:

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

Entonces tengo acceso a todos los datos de Constant en cualquier lugar

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


El module.constant de AngularJS no define una constante en el sentido estándar.

Si bien se destaca como un mecanismo de registro de proveedores, se entiende mejor en el contexto de la función module.value ( $provide.value ) relacionada. La documentación oficial establece claramente el caso de uso:

Registre un servicio de valor con el inyector $, como una cadena, un número, una matriz, un objeto o una función. Esto es la abreviatura de registrar un servicio donde la propiedad $ get de su proveedor es una función de fábrica que no toma argumentos y devuelve el servicio de valor. Eso también significa que no es posible inyectar otros servicios en un servicio de valor.

Compare esto con la documentación de module.constant ( $provide.constant ) que también establece claramente el caso de uso (énfasis mío):

Registre un servicio constante con el inyector $, como una cadena, un número, una matriz, un objeto o una función. Al igual que el valor, no es posible inyectar otros servicios en una constante. Pero a diferencia del valor, una constante puede inyectarse en una función de configuración del módulo (ver angular.Module) y no puede ser anulada por un decorador AngularJS .

Por lo tanto, la función constant AngularJS no proporciona una constante en el significado comúnmente entendido del término en el campo.

Dicho esto, las restricciones impuestas al objeto proporcionado, junto con su disponibilidad anterior a través del inyector $, sugieren claramente que el nombre se usa por analogía.

Si quisiera una constante real en una aplicación AngularJS, "proporcionaría" una de la misma manera que lo haría en cualquier programa JavaScript que sea

export const π = 3.14159265;

En Angular 2, se aplica la misma técnica.

Las aplicaciones de Angular 2 no tienen una fase de configuración en el mismo sentido que las aplicaciones de AngularJS. Además, no existe un mecanismo de decorador de servicios ( AngularJS Decorator ), pero esto no es particularmente sorprendente dado lo diferentes que son entre sí.

El ejemplo de

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

es vagamente arbitrario y un poco desagradable porque $provide.constant se está utilizando para especificar un objeto que, por cierto, también es una constante. También podrías haber escrito

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

para todos, cualquiera puede cambiar.

Ahora el argumento a favor de la comprobabilidad, burlándose de la constante, disminuye porque literalmente no cambia.

Uno no se burla de π.

Por supuesto, la semántica específica de su aplicación podría ser que su punto final podría cambiar, o su API podría tener un mecanismo de conmutación por error no transparente, por lo que sería razonable que el punto final de la API cambie bajo ciertas circunstancias.

Pero en ese caso, proporcionarlo como una representación literal de cadena de una única URL a la función constant no habría funcionado.

Un argumento mejor, y probablemente uno más alineado con la razón de la existencia de la función $provide.constant AngularJS es que, cuando se introdujo AngularJS, JavaScript no tenía un concepto de módulo estándar . En ese caso, los globales se usarían para compartir valores, mutables o inmutables, y el uso de globales es problemático.

Dicho esto, proporcionar algo como esto a través de un marco aumenta el acoplamiento a ese marco. También combina lógica angular específica con lógica que funcionaría en cualquier otro sistema.

Esto no quiere decir que sea un enfoque incorrecto o dañino, pero personalmente, si quiero una constante en una aplicación Angular 2, escribiré

export const π = 3.14159265;

tal como lo hubiera hecho si estuviera usando AngularJS.

Los más cambian las cosas...


En Angular 4, puede usar la clase de entorno para mantener todos sus globales.

Tiene environment.ts y environment.prod.ts de forma predeterminada.

Por ejemplo

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

Y luego en su servicio:

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


En Angular2, tiene la siguiente definición, que le permite configurar diferentes tipos de dependencias:

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

Comparando con Angular 1

app.service en Angular1 es equivalente a useClass en Angular2.

app.factory en Angular1 es equivalente a useFactory en Angular2.

app.constant y app.value se han simplificado para useValue con menos restricciones. es decir, ya no hay bloque de config .

app.provider : no hay equivalente en Angular 2.

Ejemplos

Para configurar con el inyector raíz:

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

O configure con el inyector de su componente:

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

provide es una mano corta para:

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

Con el inyector, obtener el valor es fácil:

var endpoint = injectorValue.get(API_ENDPOINT);


Esta es mi experiencia reciente con este escenario:

  • @ angular / cli: 1.0.0
  • nodo: 6.10.2
  • @ angular / núcleo: 4.0.0

He seguido los documentos oficiales y actualizados aquí:

here

Parece que OpaqueToken ahora está en desuso y debemos usar InjectionToken , por lo que estos son mis archivos que se ejecutan como un encanto:

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

El resultado es limpio y no hay advertencias en la consola, gracias al reciente comentario de John Papa en este número:

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

La clave fue implementar en un archivo diferente la interfaz.


La mejor manera de crear constantes de aplicación amplia en Angular 2 es mediante el uso de archivos environment.ts. La ventaja de declarar tales constantes es que puede variarlas según el entorno, ya que puede haber un archivo de entorno diferente para cada entorno.


La solución para la configuración proporcionada por el equipo angular en sí se puede encontrar here .

Aquí está todo el código relevante:

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

Ahora puede inyectar la configuración en todas partes sin usar los nombres de cadena y con el uso de su interfaz para verificaciones estáticas.

Por supuesto, puede separar la interfaz y la constante para poder suministrar diferentes valores en producción y desarrollo, por ejemplo


Puede crear una clase para su variable global y luego exportar esta clase así:

export class CONSTANT { public static message2 = [ { "NAME_REQUIRED": "Name is required" } ] public static message = { "NAME_REQUIRED": "Name is required", } }

Después de crear y exportar su clase CONSTANT , debe importar esta clase en la clase que desea usar, de esta manera:

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

Puede usar esto en constructor o ngOnInit(){} , o en cualquier método predefinido.


Si bien el enfoque de tener una clase AppSettings con una cadena constante mientras ApiEndpoint funciona, no es ideal ya que no podríamos intercambiar este ApiEndpoint real por otros valores en el momento de la prueba unitaria.

Necesitamos poder inyectar estos puntos finales de la API en nuestros servicios (piense en inyectar un servicio en otro servicio). Tampoco necesitamos crear una clase completa para esto, todo lo que queremos hacer es inyectar una cadena en nuestros servicios siendo nuestro ApiEndpoint. Para completar la excelente respuesta por pixelbits , aquí está el código completo de cómo se puede hacer en Angular 2:

Primero, debemos decirle a Angular cómo proporcionar una instancia de nuestro ApiEndpoint cuando lo solicitamos en nuestra aplicación (piense en ello como el registro de una dependencia):

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


Y luego, en el servicio, inyectamos este ApiEndpoint en el constructor del servicio y Angular nos lo proporcionará según nuestro registro anterior:

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


Si está utilizando Webpack , que recomiendo, puede configurar constantes para diferentes entornos. Esto es especialmente valioso cuando tiene valores constantes diferentes para cada entorno.

Es probable que tenga varios archivos de paquete web en su directorio /config (por ejemplo, webpack.dev.js, webpack.prod.js, etc.). Luego tendrá un custom-typings.d.ts . Los agregará allí. Aquí está el patrón general a seguir en cada archivo y un uso de muestra en un Componente.

paquete web. {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; }

Componente

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


Simplemente use una constante de Typecript

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

Puede usarlo en el inyector de dependencia usando

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


Tengo otra forma de definir constantes globales. Porque si definimos en el archivo ts, si compilamos en modo de producción, no es fácil encontrar constantes para cambiar el valor.

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

En la carpeta de la aplicación, agrego la carpeta configs / setting.json

Contenido en setting.json

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

En el módulo de la aplicación, agregue APP_INITIALIZER

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

De esta manera, puedo cambiar el valor en el archivo json más fácilmente. También lo uso para mensajes de error / advertencia constantes.


Todas las soluciones parecen ser complicadas. Estoy buscando la solución más simple para este caso y solo quiero usar constantes. Las constantes son simples. ¿Hay algo que hable en contra de la siguiente solución?

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


Un enfoque para Angular4 sería definir una constante a nivel de módulo:

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

Entonces, a su servicio:

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


Usar un archivo de propiedades que se genera durante una compilación es simple y fácil. Este es el enfoque que utiliza la CLI angular. Defina un archivo de propiedades para cada entorno y use un comando durante la compilación para determinar qué archivo se copia en su aplicación. Luego, simplemente importe el archivo de propiedades para usar.

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


Los siguientes cambios me funcionan en la versión final de Angular 2:

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

Y luego en el servicio:

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