Come posso dichiarare una variabile globale in Angular 2 / Typescript? [chiuso]


164

Vorrei alcune variabili per essere accessibile ovunque in una Angular 2nella Typescriptlingua. Come devo fare per raggiungere questo obiettivo?


2
Se sono variabili statiche non è necessario utilizzare i servizi. Basta aggiungere una variabile in alcuni file e quindi importarla ovunque ne abbiate bisogno.
Eric Martinez,

Purtroppo Angular2 ha un'eccezione in fase di esecuzione, dicendo Uncaught ReferenceError: Settings is not defined. La classe Settingscon variabili statiche pubbliche è impostata per essere esportata e importata dove utilizzata.
Sen Jacob,

So che questo post è vecchio e che ci sono molte risposte valide. Ma come ha detto Eric. Se si tratta di un valore semplice che si desidera dichiarare e al quale si può accedere attraverso tutta l'applicazione, è possibile creare una classe ed esportare la classe con una proprietà statica. Le variabili statiche sono associate a una classe anziché a un'istanza della classe. È possibile importare la classe e accedere alla proprietà da class.directly.
De Wet Ellis,

Risposte:


195

Ecco la soluzione più semplice senza ServiceObserver:

Metti le variabili globali in un file e esportale.

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

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

Per usare i globi in un altro file usa importun'istruzione: import * as myGlobals from 'globals';

Esempio:

// 
// ===== 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";

         ...

        }
    }

Grazie @ eric-martinez


3
Errore nella dichiarazione di importazione. ho dovuto usareimport * as globs from 'globals'
Mike M

13
Perché hai usato "richiedi" invece di importare da?
Ayyash,

4
Vorrei usare export constinvece di export var- vuoi davvero assicurarti che quelle variabili globali non possano essere cambiate
Michal Boska,

1
L'importazione in questo modo non è più valida in TypeScript. Aggiorna la tua risposta. Corretto sarebbe:import * as myGlobals from 'globals'
Mick

7
import * as myGlobals from './path/to/globals';
Timothy Zorn,

89

Mi piace anche la soluzione di @supercobra. Vorrei solo migliorarlo leggermente. Se si esporta un oggetto che contiene tutte le costanti, si può semplicemente utilizzare ES6 importazione del modulo senza l'utilizzo richiede .

Ho anche usato Object.freeze per trasformare le proprietà in vere costanti. Se sei interessato all'argomento, puoi leggere questo post .

// global.ts

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

Fare riferimento al modulo usando import.

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

export class HeroService {
    private baseApiUrl = GlobalVariable.BASE_API_URL;

    //... more code
}

questa per me è la soluzione migliore perché (1) è la più semplice con meno quantità di codice e (2) non richiede di iniettare un servizio dannato in ogni singolo componente o luogo in cui si desidera utilizzarlo, né lo fa richiede di registrarlo in @NgModule. Non posso per la vita di me capire perché sarebbe necessario creare un servizio Angular 2 per fare questo, ma forse c'è qualcosa che sto trascurando? Sto usando questa ottima soluzione per ora, ma per favore fatemi sapere perché le altre risposte più complicate qui sono migliori?
FireDragon,

8
GlobalVariable non è una variabile. È una costante.
Priya R,

@PriyaR LOL, sì, hai ragione. Ho ipotizzato che l'obiettivo principale della domanda fosse avere un modo sicuro per accedere ad alcuni valori a livello globale, quindi ho improvvisato. Altrimenti, sentiti libero di cambiare const in var, otterrai la tua variabile.
Tim Hong

Il lato negativo di Object.freeze è che i valori non vengono digitati. Ad ogni modo, racchiudere i valori in una classe è un progetto migliore dal mio punto di vista. Quindi dobbiamo scegliere tra proprietà tipizzate e costanti vere.
Harps,

come impostare GlobalVariable.BASE_API_URL in un altro componente ..?
Sunil Chaudhry,

59

Un servizio condiviso è l'approccio migliore

export class SharedService {
  globalVar:string;
}

Ma devi essere molto attento quando lo registri per poter condividere una singola istanza per l'intera applicazione. È necessario definirlo al momento della registrazione dell'applicazione:

bootstrap(AppComponent, [SharedService]);

ma non per definirlo di nuovo all'interno degli providersattributi dei componenti:

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

Altrimenti verrà creata una nuova istanza del servizio per il componente e i suoi componenti secondari.

Puoi dare un'occhiata a questa domanda su come funzionano l'iniezione di dipendenza e gli iniettori gerarchici in Angular2:

Puoi notare che puoi anche definire Observableproprietà nel servizio per notificare parti dell'applicazione quando cambiano le proprietà globali:

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

Vedi questa domanda per maggiori dettagli:


Sembra che questo sia diverso però. Sembra che Rat2000 pensi che la nostra risposta sia sbagliata. Di solito lascio questa decisione ad altri piuttosto che fornire risposte concorrenti, ma se è convinto che le nostre risposte siano sbagliate, penso che sia valido. I documenti a cui si è collegato in un commento alla mia risposta menzionano che è SCONTATO ma non vedo alcun svantaggio e gli argomenti nei documenti sono piuttosto deboli. È anche abbastanza comune aggiungere provider a bootstrap. Quale sarebbe lo scopo di questa discussione comunque. E che dire HTTP_PROVIDERSe simili, non dovrebbero essere aggiunti bootstrap()?
Günter Zöchbauer,

2
Sì, ho appena letto l'argomento e la sezione nel documento. Honnestly non capisco davvero perché sia ​​scoraggiato dal doc. È un modo per definire una divisione logica: cos'è il core di Angular2 (provider di routing, provider http) durante il bootstrap e cosa è specifico dell'applicazione nell'iniettore del componente dell'applicazione. Detto questo, possiamo avere solo un subiniettore (quello dell'applicazione) per quello principale (definito durante l'avvio del bootstrap). Mi manca qualcosa? Inoltre nel documento relativo agli iniettori gerarchici, i fornitori di servizi sono definiti all'interno dell'iniettore di radice ;-)
Thierry Templier,

3
L'unico argomento che vedo è che mantenere l'ambito il più stretto possibile e usare il componente radice è almeno in teoria leggermente più stretto dell'uso bootstrap()ma in pratica non importa. Penso che elencarli in boostrap()rende il codice più facile da capire. Un componente ha provider, direttive, un modello. Trovo questo sovraccarico senza fornitori globali elencati anche lì. Quindi preferisco bootstrap().
Günter Zöchbauer,

2
e come si fa riferimento a tali variabili globali? anche dopo l'avvio del servizio, la chiamata alert(globalVar)provoca un errore.
phil294,

Non l'ho ancora provato, ma vorrai qualcosa di simile: alert (this.SharedService.globalVar)
trees_are_great

39

Vedere ad esempio Angolare 2 - Implementazione di servizi condivisi

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

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

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

o fornire valori individuali

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

class MyComponent {
  constructor(@Inject('myConfigValue') private myConfigValue:string) {
    console.log(myConfigValue);
  }
}

Da Angular2 beta 7 (credo) non dovresti registrare il tuo servizio direttamente nel componente root (aka bootstrap). È comunque possibile iniettare lì un provider specifico se si desidera sovrascrivere qualcosa nella propria applicazione.
Mihai,

1
Non sono sicuro cosa intendi. Ovviamente puoi registrare un servizio in bootstrap(). bootstrap()e il componente radice sono due cose diverse. Quando chiami bootstrap(AppComponent, [MyService]), registra il servizio boostrap()ed AppComponentè il componente principale. I documenti menzionano da qualche parte che è preferibile registrare i provider (servizio) nei componenti root providers: ['MyService']ma non ho ancora trovato alcun argomento a favore o contro bootstrap()o componente root.
Günter Zöchbauer,

Puoi trovare il tuo argomento nella sezione angolare 2guide Dependency Injection ( angular.io/docs/ts/latest/guide/dependency-injection.html ). Come si suol dire, puoi farlo ma è SCONTATO. Questo utente sta chiedendo il modo migliore per iniettare qualcosa che chiaramente la tua soluzione non è corretta. lo stesso vale per @ThierryTemplier
Mihai il

1
Penso che la citazione più importante del documento Angular sia "L'opzione del fornitore bootstrap è pensata per configurare e sovrascrivere i servizi preregistrati di Angular, come il suo supporto di routing". Raramente metto i servizi nel bootstrap da solo, e sono felice di vedere che i documenti ora lo suggeriscono.
Mark Rajcok,

1
non dimenticare di esportare la classe
Demodave,

15

Crea la classe Globals in app / globals.ts :

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

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

Nel tuo 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 : è possibile aggiungere il fornitore del servizio Globals direttamente al modulo anziché al componente e non sarà necessario aggiungere come fornitore a ogni componente di quel modulo.

@NgModule({
    imports: [...],
    declarations: [...],
    providers: [ Globals ],
    bootstrap: [ AppComponent ]
})
export class AppModule {
}

Questa è la risposta migliore, poiché offre un approccio più portatile rispetto alla necessità di aggiungere il servizio a ciascun componente attraverso l'app. Grazie!
Vidal Quevedo,

5
Il codice funziona. Ma nota che l'iniezione di classe Globalscon l'aggiunta anche a providers: [ ... ]significa che non puoi modificare un valore all'interno di un componente e quindi chiedere il valore aggiornato all'interno di un secondo componente. Ogni volta che si inietta Globalsè una nuova istanza. Se si desidera modificare questo comportamento, semplicemente NON aggiungere Globals come provider.
Timo Bähr,

solo una nota, dovrebbe essere@Injectable()
mast3rd3mon

11

IMHO per Angular2 (v2.2.3) il modo migliore è aggiungere servizi che contengono la variabile globale e iniettarli in componenti senza il providerstag all'interno @Componentdell'annotazione. In questo modo è possibile condividere informazioni tra i componenti.

Un servizio di esempio che possiede una variabile globale:

import { Injectable } from '@angular/core'

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

Un componente di esempio che aggiorna il valore della variabile globale:

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

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

  constructor(private someSharedService: SomeSharedService) { }

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

Un componente di esempio che legge il valore della variabile globale:

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

Nota che nonproviders: [ SomeSharedService ] dovrebbe essere aggiunto alla tua annotazione. Non aggiungendo questa riga, l'iniezione ti darà sempre la stessa istanza di . Se aggiungi la riga, viene iniettata un'istanza appena creata.@ComponentSomeSharedService


Ma senza aggiungere la linea di provider, ho avuto un errore del genere:Unhandled Promise rejection: No provider for SomeSharedService
Rocky

Vedo. Dovrei aggiungere providers: [SomeSharedService]il file del modulo genitore. Grazie.
Rocky,

Questo non funziona quando siamo moduli di caricamento pigri.
lpradhap,

9

Non conosco il modo migliore, ma il modo più semplice se si desidera definire una variabile globale all'interno di un componente è usare la windowvariabile per scrivere in questo modo:

window.GlobalVariable = "what ever!"

non è necessario passarlo al bootstrap o importarlo in altri luoghi ed è accessibile globalmente a tutti i JS (non solo ai 2 componenti angolari).


1
Direi che è il modo peggiore. L'uso di una variabile statica non è più complicato, ma non è neanche così brutto ;-)
Günter Zöchbauer,

2
Sono d'accordo che rende difficile da gestire. Comunque ho finito per usarli nello sviluppo fino a quando non trovo quello che voglio mettere in produzione. Nella variabile statica devi importarli ancora e ancora ovunque tu voglia usare, inoltre c'era un caso che stavo producendo la mia vista in movimento con jquery in componenti angolari - non c'era un modello e per aggiungere eventi al DOM prodotto usando statico la variabile è dolore.
Mahdi Jadaliha,

1
Inoltre, non è statico, puoi cambiare il valore da qualsiasi luogo!
Mahdi Jadaliha,

1
Distrugge anche il rendering lato server. Evita di manipolare direttamente la finestra o il documento.
Erik Honn,

1
Concordato. ma personalmente non seguo alcuna linea guida nella mia vita (se potessi fare di meglio).
Mahdi Jadaliha,

7

Questo è il modo in cui lo uso:

global.ts

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

per usarlo basta importare così:

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
}

MODIFICATO: "_" eliminato con prefisso come raccomandato.


Non utilizzare "_" come prefisso per proprietà private. github.com/Microsoft/TypeScript/wiki/Coding-guidelines
crh225

4

Penso che il modo migliore sia condividere un oggetto con variabili globali in tutta la tua applicazione esportandolo e importandolo dove vuoi.

Innanzitutto creare un nuovo file .ts , ad esempio globals.ts e dichiarare un oggetto. Gli ho dato un tipo di oggetto ma puoi anche usare un qualsiasi tipo o {}

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

Dopo di ciò importalo

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

E usalo

console.log(globalVariables);

3

Mi piace la risposta di @supercobra, ma vorrei usare la parola chiave const in quanto è già disponibile in ES6:

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

export const sep='/';
export const version: string="22.2.2"; 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.