¿Cómo puedo declarar una variable global en Angular 2 / Typecript? [cerrado]

164

Me gustaría que algunas variables para que sea accesible por todos lados en una Angular 2en el Typescriptlenguaje. ¿Cómo debo hacer para lograr esto?

supercobra
fuente
2
Si son variables estáticas no hay necesidad de usar servicios. Simplemente agregue una variable en algún archivo y luego impórtela donde sea que la necesite.
Eric Martinez
Lamentablemente, Angular2 tiene una excepción en tiempo de ejecución, diciendo Uncaught ReferenceError: Settings is not defined. La clase Settingscon variables públicas estáticas está configurada para exportar y ha importado donde solía.
Sen Jacob,
Sé que esta publicación es antigua y que hay muchas respuestas válidas. Pero como mencionó Eric. Si es un valor simple que desea declarar y tiene acceso a través de su aplicación, puede crear una clase y exportar la clase con una propiedad estática. Las variables estáticas están asociadas con una clase en lugar de una instancia de la clase. Puede importar la clase y podrá acceder a la propiedad desde la clase directamente.
De Wet Ellis

Respuestas:

195

Aquí está la solución más simple w o / Serviceni Observer:

Coloque las variables globales en un archivo y expórtelas.

//
// ===== File globals.ts    
//
'use strict';

export const sep='/';
export const version: string="22.2.2";    

Para usar globales en otro archivo, use una importdeclaración: import * as myGlobals from 'globals';

Ejemplo:

// 
// ===== File heroes.component.ts    
//
import {Component, OnInit} from 'angular2/core';
import {Router} from 'angular2/router';
import {HeroService} from './hero.service';
import {HeroDetailComponent} from './hero-detail.component';
import {Hero} from './hero';
import * as myGlobals from 'globals'; //<==== this one (**Updated**)

export class HeroesComponent implements OnInit {
    public heroes: Hero[];
    public selectedHero: Hero;
    // 
    //
    // Here we access the global var reference.
    //  
    public helloString: string="hello " + myGlobals.sep + " there";

         ...

        }
    }

Gracias @ eric-martinez

supercobra
fuente
3
Tengo un error en la declaración de importación. tuvo que usarimport * as globs from 'globals'
Mike M
13
¿Por qué usaste "require" en lugar de importar desde?
Ayyash el
44
Yo usaría en export constlugar de export var- realmente quieres asegurarte de que esas variables globales no puedan cambiarse
Michal Boska
1
Importar así ya no es válido en TypeScript. Por favor actualice su respuesta. Correcto sería:import * as myGlobals from 'globals'
Mick
77
import * as myGlobals from './path/to/globals';
Timothy Zorn
89

También me gusta la solución de @supercobra. Solo me gustaría mejorarlo un poco. Si exporta un objeto que contiene todas las constantes, simplemente puede usar es6 para importar el módulo sin usar require .

También usé Object.freeze para hacer que las propiedades se conviertan en constantes verdaderas. Si está interesado en el tema, puede leer esta publicación .

// global.ts

 export const GlobalVariable = Object.freeze({
     BASE_API_URL: 'http://example.com/',
     //... more of your variables
 });

Consulte el módulo utilizando importación.

//anotherfile.ts that refers to global constants
import { GlobalVariable } from './path/global';

export class HeroService {
    private baseApiUrl = GlobalVariable.BASE_API_URL;

    //... more code
}
Tim Hong
fuente
Para mí, esta es la mejor solución porque (1) es la más simple con la menor cantidad de código y (2) no requiere que inyecte algún servicio maldito en cada componente o lugar en el que desea usarlo, ni requieren que lo registres en @NgModule. Por mi vida no puedo entender por qué sería necesario crear un Servicio Angular 2 para hacer esto, pero ¿quizás hay algo que estoy pasando por alto? Estoy usando esta gran solución por ahora, pero por favor, hágame saber por qué las otras respuestas más complicadas aquí son mejores.
FireDragon
8
Su GlobalVariable no es una variable. Es una constante.
Priya R
@PriyaR LOL, sí, tienes razón. Asumí que el objetivo principal de la pregunta era tener una forma segura de acceder a algunos valores a nivel mundial, así que improvisé. De lo contrario, siéntase libre de cambiar const a var, obtendrá su variable.
Tim Hong
La desventaja de Object.freeze es que los valores no están escritos. De todos modos, envolver valores en una clase es un mejor diseño desde mi perspectiva. Entonces tenemos que elegir entre propiedades escritas y constantes verdaderas.
Harps
¿Cómo configurar GlobalVariable.BASE_API_URL en otro componente ...?
Sunil Chaudhry
59

Un servicio compartido es el mejor enfoque

export class SharedService {
  globalVar:string;
}

Pero debe tener mucho cuidado al registrarlo para poder compartir una sola instancia para toda su aplicación. Debe definirlo al registrar su aplicación:

bootstrap(AppComponent, [SharedService]);

pero no para definirlo nuevamente dentro de los providersatributos de sus componentes:

@Component({
  (...)
  providers: [ SharedService ], // No
  (...)
})

De lo contrario, se creará una nueva instancia de su servicio para el componente y sus subcomponentes.

Puede echar un vistazo a esta pregunta sobre cómo funcionan la inyección de dependencia y los inyectores jerárquicos en Angular2:

Puede observar que también puede definir Observablepropiedades en el servicio para notificar partes de su aplicación cuando cambian sus propiedades globales:

export class SharedService {
  globalVar:string;
  globalVarUpdate:Observable<string>;
  globalVarObserver:Observer;

  constructor() {
    this.globalVarUpdate = Observable.create((observer:Observer) => {
      this.globalVarObserver = observer;
    });
  }

  updateGlobalVar(newValue:string) {
    this.globalVar = newValue;
    this.globalVarObserver.next(this.globalVar);
  }
}

Vea esta pregunta para más detalles:

Thierry Templier
fuente
Sin embargo, parece que este es diferente. Parece que @ Rat2000 cree que nuestra respuesta es incorrecta. Por lo general, dejo esta decisión a otras personas que no sean personas que brindan respuestas competitivas, pero si está convencido de que nuestras respuestas son incorrectas, entonces creo que es válido. Los documentos a los que se vinculó en un comentario a mi respuesta mencionan que está DESCUBIERTO, pero no veo ninguna desventaja y los argumentos en los documentos son bastante débiles. También es bastante común agregar proveedores a bootstrap. ¿Cuál sería el propósito de este argumento de todos modos? ¿Y qué pasa HTTP_PROVIDERSy similares, tampoco deberían agregarse bootstrap()?
Günter Zöchbauer
2
Sí, acabo de leer el argumento y la sección en el documento. Sinceramente, realmente no entiendo por qué está desanimado por el documento. ¿Es una manera de definir una división lógica? Dicho esto, solo podemos tener un subinyector (el de la aplicación) para el raíz (definido al arrancar). ¿Echo de menos algo? Además, en el documento sobre inyectores jerárquicos, los proveedores de servicios se definen dentro del inyector raíz ;-)
Thierry Templier
3
El único argumento que veo es que mantener el alcance lo más estrecho posible y usar el componente raíz es al menos en teoría un poco más estrecho que usarlo, bootstrap()pero en la práctica no importa. Creo que enumerarlos boostrap()hace que el código sea más fácil de entender. Un componente tiene proveedores, directivas, una plantilla. Encuentro esto sobrecargado sin los proveedores globales enumerados allí también. Por eso lo prefiero bootstrap().
Günter Zöchbauer
2
¿Y cómo se hace referencia a tales variables globales? incluso después de iniciar el servicio, llamar a los alert(globalVar)resultados en un error.
phil294
Todavía no lo he probado, pero querrás algo como: alert (this.SharedService.globalVar)
trees_are_great
39

Ver por ejemplo Angular 2 - Implementación de servicios compartidos

@Injectable() 
export class MyGlobals {
  readonly myConfigValue:string = 'abc';
}

@NgModule({
  providers: [MyGlobals],
  ...
})

class MyComponent {
  constructor(private myGlobals:MyGlobals) {
    console.log(myGlobals.myConfigValue);
  }
}

o proporcionar valores individuales

@NgModule({
  providers: [{provide: 'myConfigValue', useValue: 'abc'}],
  ...
})

class MyComponent {
  constructor(@Inject('myConfigValue') private myConfigValue:string) {
    console.log(myConfigValue);
  }
}
Günter Zöchbauer
fuente
Desde Angular2 beta 7 (creo), no debe registrar su servicio directamente en el componente raíz (también conocido como bootstrap). Sin embargo, puede inyectar allí un proveedor específico si desea anular algo en su aplicación.
Mihai
1
No estoy seguro de lo que quieres decir. Por supuesto, puede registrar un servicio en bootstrap(). bootstrap()y el componente raíz son dos cosas diferentes. Cuando llama bootstrap(AppComponent, [MyService]), registra el servicio boostrap()y AppComponentes el componente raíz. Los documentos mencionan en alguna parte que es preferible registrar proveedores (servicio) en los componentes raíz, providers: ['MyService']pero todavía no he encontrado ningún argumento a favor o en contra del bootstrap()componente raíz.
Günter Zöchbauer
Puede encontrar su argumento en la sección de inyección de dependencia de la guía angular 2 ( angular.io/docs/ts/latest/guide/dependency-injection.html ). Como dicen, puedes hacerlo pero está DESCURRIDO. Este usuario está pidiendo la mejor manera de inyectar algo que claramente su solución no es correcta. Lo mismo ocurre con @ThierryTemplier
Mihai
1
Creo que la cita más importante del documento de Angular es "La opción del proveedor de bootstrap está diseñada para configurar y anular los servicios prerregistrados de Angular, como su soporte de enrutamiento". Raramente pongo servicios en bootstrap, y me alegra ver que los documentos ahora lo sugieren.
Mark Rajcok
1
no olvides exportar la clase
Desmodave
15

Crear clase global en app / globals.ts :

import { Injectable } from '@angular/core';

Injectable()
export class Globals{
    VAR1 = 'value1';
    VAR2 = 'value2';
}

En su componente:

import { Globals } from './globals';

@Component({
    selector: 'my-app',
    providers: [ Globals ],
    template: `<h1>My Component {{globals.VAR1}}<h1/>`
})
export class AppComponent {
    constructor(private globals: Globals){
    }
}

Nota : Puede agregar el proveedor de servicios Globals directamente al módulo en lugar del componente, y no necesitará agregarlo como proveedor a cada componente de ese módulo.

@NgModule({
    imports: [...],
    declarations: [...],
    providers: [ Globals ],
    bootstrap: [ AppComponent ]
})
export class AppModule {
}
gradosevic
fuente
Esta es la mejor respuesta, ya que ofrece un enfoque más portátil que tener que agregar el servicio a cada componente en la aplicación. ¡Gracias!
Vidal Quevedo
55
El código está funcionando Pero tenga en cuenta que inyectar a la clase Globalscon agregarlo también providers: [ ... ]significa que no puede cambiar un valor dentro de un componente y luego solicitar el valor actualizado dentro de un segundo componente. Cada vez que se inyecta Globalses una instancia nueva. Si desea cambiar este comportamiento, simplemente NO agregue Globals como proveedor.
Timo Bähr
solo una nota, debería ser@Injectable()
mast3rd3mon
11

En mi humilde opinión para Angular2 (v2.2.3), la mejor manera es agregar servicios que contengan la variable global e inyectarlos en componentes sin la providersetiqueta dentro del@Component anotación. De esta manera, puede compartir información entre componentes.

Un servicio de muestra que posee una variable global:

import { Injectable } from '@angular/core'

@Injectable()
export class SomeSharedService {
  public globalVar = '';
}

Un componente de muestra que actualiza el valor de su variable global:

import { SomeSharedService } from '../services/index';

@Component({
  templateUrl: '...'
})
export class UpdatingComponent {

  constructor(private someSharedService: SomeSharedService) { }

  updateValue() {
    this.someSharedService.globalVar = 'updated value';
  }
}

Un componente de muestra que lee el valor de su variable global:

import { SomeSharedService } from '../services/index';

@Component({
  templateUrl: '...'
})
export class ReadingComponent {

  constructor(private someSharedService: SomeSharedService) { }

  readValue() {
    let valueReadOut = this.someSharedService.globalVar;
    // do something with the value read out
  }
}

Tenga en cuenta que providers: [ SomeSharedService ]debe no ser añadido a su @Componentanotación. Al no agregar esta línea, la inyección siempre le dará la misma instancia de SomeSharedService. Si agrega la línea, se inyecta una instancia recién creada.

Timo Bähr
fuente
Pero sin agregar la línea de proveedores, recibí un error como este:Unhandled Promise rejection: No provider for SomeSharedService
Rocky
Veo. Debo agregar providers: [SomeSharedService]el archivo del módulo principal. Gracias.
Rocky
Esto no funciona cuando somos módulos de carga diferidos.
lpradhap
9

No sé la mejor manera, pero la manera más fácil si desea definir una variable global dentro de un componente es usar una windowvariable para escribir así:

window.GlobalVariable = "what ever!"

no necesita pasarlo a bootstrap o importarlo a otros lugares, y es accesible globalmente a todos los JS (no solo a los componentes angulares 2).

Mahdi Jadaliha
fuente
1
Yo diría que es la peor manera. Usar una variable estática no es más complicado, pero tampoco es tan feo ;-)
Günter Zöchbauer
2
Estoy de acuerdo en que es difícil de manejar. Sin embargo, terminé de usarlos en desarrollo hasta que encuentro lo que quiero poner en producciones. En la variable estática, debe importarlos una y otra vez en cualquier lugar que desee usar, además de que estaba produciendo mi vista sobre la marcha con jquery en componentes angulares: no había plantilla y para agregar eventos al DOM producido usando estática variable es el dolor.
Mahdi Jadaliha
1
Además, no es estático, ¡puedes cambiar el valor desde cualquier lugar!
Mahdi Jadaliha
1
También destruye la representación del lado del servidor. Manténgase alejado de manipular directamente la ventana o el documento.
Erik Honn
1
Convenido. pero personalmente no sigo ninguna directriz en mi vida (si pudiera hacerlo mejor que eso).
Mahdi Jadaliha
7

Así es como lo uso:

global.ts

export var server: string = 'http://localhost:4200/';
export var var2: number = 2;
export var var3: string = 'var3';

para usarlo solo importa así:

import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import * as glob from '../shared/global'; //<== HERE

@Injectable()
export class AuthService {
    private AuhtorizationServer = glob.server
}

EDITADO: Droped "_" con el prefijo recomendado.

Guilherme Teubl
fuente
No use "_" como prefijo para propiedades privadas. github.com/Microsoft/TypeScript/wiki/Coding-guidelines
crh225
4

Creo que la mejor manera es compartir un objeto con variables globales en toda su aplicación exportándolo e importándolo donde lo desee.

Primero cree un nuevo archivo .ts , por ejemplo globals.ts y declare un objeto. Le di un tipo de objeto, pero también podría usar cualquier tipo o {}

export let globalVariables: Object = {
 version: '1.3.3.7',
 author: '0x1ad2',
 everything: 42
};

Después de eso importalo

import {globalVariables} from "path/to/your/globals.ts"

Y úsalo

console.log(globalVariables);
0x1ad2
fuente
3

Me gusta la respuesta de @supercobra, pero usaría la palabra clave const como está en ES6 ya disponible:

//
// ===== File globals.ts    
//
'use strict';

export const sep='/';
export const version: string="22.2.2"; 
Zolcsi
fuente