Wie kann ich eine globale Variable in Angular 2 / Typescript deklarieren? [geschlossen]

164

Ich möchte, dass einige Variablen überall Angular 2in der TypescriptSprache verfügbar sind. Wie soll ich das erreichen?

Superkobra
quelle
2
Wenn es sich um statische Variablen handelt, müssen keine Dienste verwendet werden. Fügen Sie einfach eine Variable in eine Datei ein und importieren Sie sie dann überall dort, wo Sie sie benötigen.
Eric Martinez
Leider hat Angular2 zur Laufzeit eine Ausnahme Uncaught ReferenceError: Settings is not defined. Die Klasse Settingsmit öffentlichen statischen Variablen ist auf Export eingestellt und wurde dort importiert, wo sie verwendet wurde.
Sen Jacob
Ich weiß, dass dieser Beitrag alt ist und dass es viele gültige Antworten gibt. Aber wie Eric schon sagte. Wenn es sich um einen einfachen Wert handelt, den Sie deklarieren und auf den Sie in Ihrer gesamten Anwendung zugreifen möchten, können Sie eine Klasse erstellen und die Klasse mit einer statischen Eigenschaft exportieren. Statische Variablen sind eher einer Klasse als einer Instanz der Klasse zugeordnet. Sie können die Klasse importieren und von class.directly auf die Eigenschaft zugreifen.
De Wet Ellis

Antworten:

194

Hier ist die einfachste Lösung , w / o Servicenoch Observer:

Fügen Sie die globalen Variablen in eine Datei ein und exportieren Sie sie.

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

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

Verwenden Sie eine importAnweisung, um Globals in einer anderen Datei zu verwenden : import * as myGlobals from 'globals';

Beispiel:

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

         ...

        }
    }

Danke @ eric-martinez

Superkobra
quelle
3
Ich habe einen Fehler in der Importanweisung erhalten. musste verwendenimport * as globs from 'globals'
Mike M
13
Warum haben Sie "require" anstelle von import from verwendet?
Ayyash
4
Ich würde export constanstelle von export var- Sie möchten wirklich sicherstellen, dass diese globalen Variablen nicht geändert werden können
Michal Boska
1
Ein solcher Import ist in TypeScript nicht mehr gültig. Bitte aktualisieren Sie Ihre Antwort. Richtig wäre:import * as myGlobals from 'globals'
Mick
7
import * as myGlobals from './path/to/globals';
Timothy Zorn
89

Ich mag auch die Lösung von @supercobra. Ich möchte es nur leicht verbessern. Wenn Sie ein Objekt exportieren, das alle Konstanten enthält, können Sie das Modul einfach mit es6 importieren, ohne require zu verwenden .

Ich habe auch Object.freeze verwendet, um die Eigenschaften zu wahren Konstanten zu machen. Wenn Sie sich für das Thema interessieren, können Sie diesen Beitrag lesen .

// global.ts

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

Verweisen Sie das Modul mit Import.

//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
quelle
Für mich ist dies die beste Lösung, da (1) es die einfachste mit der geringsten Menge an Code ist und (2) Sie nicht in jede einzelne Komponente oder jeden Ort, an dem Sie sie verwenden möchten, einen verdammten Service einfügen müssen, und dies auch nicht Sie müssen es in @NgModule registrieren. Ich kann für mein ganzes Leben nicht herausfinden, warum es notwendig wäre, einen Angular 2-Dienst zu erstellen, um dies zu tun, aber vielleicht gibt es etwas, das ich übersehen habe? Ich verwende diese großartige Lösung derzeit, aber lassen Sie mich bitte wissen, warum die anderen komplizierteren Antworten hier besser sind.
FireDragon
8
Ihre GlobalVariable ist keine Variable. Es ist eine Konstante.
Priya R
@PriyaR LOL, ja, du hast recht. Ich nahm an, dass das Hauptziel der Frage darin bestand, einen sicheren Weg zu finden, um global auf einige Werte zuzugreifen, und improvisierte. Andernfalls können Sie const in var ändern. Sie erhalten Ihre Variable.
Tim Hong
Der Nachteil von Object.freeze ist, dass Werte nicht eingegeben werden. Wie auch immer, das Einschließen von Werten in eine Klasse ist aus meiner Sicht ein besseres Design. Wir müssen also zwischen typisierten Eigenschaften und wahren Konstanten wählen.
Harfen
Wie setze ich GlobalVariable.BASE_API_URL in einer anderen Komponente?
Sunil Chaudhry
59

Ein gemeinsamer Dienst ist der beste Ansatz

export class SharedService {
  globalVar:string;
}

Sie müssen jedoch bei der Registrierung sehr vorsichtig sein, um eine einzelne Instanz für Ihre gesamte Anwendung freigeben zu können. Sie müssen es bei der Registrierung Ihrer Bewerbung definieren:

bootstrap(AppComponent, [SharedService]);

aber nicht erneut innerhalb der providersAttribute Ihrer Komponenten zu definieren :

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

Andernfalls wird eine neue Instanz Ihres Dienstes für die Komponente und ihre Unterkomponenten erstellt.

Sie können sich diese Frage ansehen, wie Abhängigkeitsinjektion und hierarchische Injektoren in Angular2 funktionieren:

Sie können feststellen, dass Sie Observableim Service auch Eigenschaften definieren können , um Teile Ihrer Anwendung zu benachrichtigen, wenn sich Ihre globalen Eigenschaften ändern:

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

Siehe diese Frage für weitere Details:

Thierry Templier
quelle
Scheint, dass dies anders ist. @ Rat2000 scheint unsere Antwort falsch zu sein. Normalerweise überlasse ich diese Entscheidung anderen als Leuten, die konkurrierende Antworten geben, aber wenn er überzeugt ist, dass unsere Antworten falsch sind, denke ich, dass sie gültig sind. Die Dokumente, auf die er in einem Kommentar zu meiner Antwort verwiesen hat, erwähnen, dass es entmutigt ist, aber ich sehe keinen Nachteil und die Argumente in den Dokumenten sind ziemlich schwach. Es ist auch durchaus üblich, Anbieter zum Bootstrap hinzuzufügen. Was wäre der Zweck dieses Arguments überhaupt. Und was ist mit HTTP_PROVIDERSund ähnlich, sollten sie auch nicht hinzugefügt werden bootstrap()?
Günter Zöchbauer
2
Ja, ich habe gerade das Argument und den Abschnitt im Dokument gelesen. Ehrlich gesagt verstehe ich nicht wirklich, warum es vom Dokument abgeraten wird. Ist es eine Möglichkeit, eine logische Aufteilung zu definieren: Was ist Angular2-Kern spezifisch (Routing-Anbieter, http-Anbieter) beim Bootstrapping und was ist anwendungsspezifisch im Anwendungskomponenten-Injektor. Das heißt, wir können nur einen Subinjektor (den Anwendungsinjektor) für den Root-Injektor (definiert beim Bootstrapping) haben. Vermisse ich etwas Darüber hinaus werden in der Dokumentation zu hierarchischen Injektoren Dienstanbieter innerhalb des Root-Injektors definiert ;-)
Thierry Templier
3
Das einzige Argument, das ich sehe, ist, dass es zumindest theoretisch etwas enger ist, den Umfang so eng wie möglich zu halten und die Wurzelkomponente zu verwenden, bootstrap()aber in der Praxis spielt es keine Rolle. Ich denke, dass das Auflisten in boostrap()den Code verständlicher macht. Eine Komponente hat Anbieter, Direktiven und eine Vorlage. Ich finde das überlastet, ohne dass dort auch globale Anbieter aufgeführt sind. Deshalb bevorzuge ich bootstrap().
Günter Zöchbauer
2
und wie verweist man auf solche globalen Variablen? Selbst nach dem Booten des Dienstes führt das Aufrufen alert(globalVar)zu einem Fehler.
Phil294
Ich habe das noch nicht ausprobiert, aber Sie möchten etwas wie: alert (this.SharedService.globalVar)
tree_are_great
39

Siehe zum Beispiel Angular 2 - Implementierung von Shared Services

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

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

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

oder individuelle Werte angeben

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

class MyComponent {
  constructor(@Inject('myConfigValue') private myConfigValue:string) {
    console.log(myConfigValue);
  }
}
Günter Zöchbauer
quelle
Seit Angular2 Beta 7 (glaube ich) sollten Sie Ihren Dienst nicht direkt in der Root-Komponente (auch bekannt als Bootstrap) registrieren. Sie können dort jedoch einen bestimmten Anbieter einfügen, wenn Sie etwas in Ihrer Anwendung überschreiben möchten.
Mihai
1
Nicht sicher was du meinst. Natürlich können Sie einen Dienst in registrieren bootstrap(). bootstrap()und Wurzelkomponente sind zwei verschiedene Dinge. Wenn Sie anrufen bootstrap(AppComponent, [MyService]), registrieren Sie den Dienst in boostrap()und AppComponentist die Stammkomponente. In den Dokumenten wird irgendwo erwähnt, dass es bevorzugt ist, Anbieter (Dienste) in den Stammkomponenten zu registrieren, providers: ['MyService']aber ich habe noch kein Argument für oder gegen bootstrap()oder Stammkomponente gefunden.
Günter Zöchbauer
Sie finden Ihr Argument im Abschnitt Angular 2guide Dependency Injection ( angle.io/docs/ts/latest/guide/dependency-injection.html ). Wie sie sagen, können Sie es tun, aber es ist entmutigt. Dieser Benutzer fragt nach dem besten Weg, um etwas zu injizieren, bei dem Ihre Lösung eindeutig nicht korrekt ist. Gleiches gilt für @ThierryTemplier
Mihai
1
Ich denke, das wichtigere Zitat aus dem Angular-Dokument lautet: "Die Bootstrap-Provider-Option dient zum Konfigurieren und Überschreiben von Angulars eigenen vorregistrierten Diensten, wie z. B. der Routing-Unterstützung." Ich habe selbst selten Dienste in Bootstrap gestellt, und ich bin froh, dass die Dokumente dies jetzt vorschlagen.
Mark Rajcok
1
Vergessen Sie nicht, die Klasse zu exportieren
Demodave
15

Erstellen Sie die Globals-Klasse in app / globals.ts :

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

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

In Ihrer Komponente:

import { Globals } from './globals';

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

Hinweis : Sie können den Globals-Dienstanbieter anstelle der Komponente direkt zum Modul hinzufügen, und Sie müssen nicht jeder Komponente in diesem Modul als Anbieter hinzufügen.

@NgModule({
    imports: [...],
    declarations: [...],
    providers: [ Globals ],
    bootstrap: [ AppComponent ]
})
export class AppModule {
}
gradosevic
quelle
Dies ist die beste Antwort, da sie einen portableren Ansatz bietet, als den Dienst jeder Komponente in der App hinzufügen zu müssen. Danke dir!
Vidal Quevedo
5
Der Code funktioniert. Beachten Sie jedoch, dass das Injizieren einer Klasse Globalsdurch Hinzufügen zu auch providers: [ ... ]bedeutet, dass Sie einen Wert innerhalb einer Komponente nicht ändern und dann innerhalb einer zweiten Komponente nach dem aktualisierten Wert fragen können. Jedes Mal, wenn Sie injizieren Globals, ist es eine neue Instanz. Wenn Sie dieses Verhalten ändern möchten, fügen Sie es einfach NICHTGlobals als Anbieter hinzu.
Timo Bähr
Nur eine Anmerkung, es sollte sein@Injectable()
mast3rd3mon
11

IMHO für Angular2 (v2.2.3) besteht der beste Weg darin, Dienste hinzuzufügen, die die globale Variable enthalten, und sie in Komponenten ohne das providersTag in der @ComponentAnmerkung einzufügen. Auf diese Weise können Sie Informationen zwischen Komponenten austauschen.

Ein Beispieldienst, der eine globale Variable besitzt:

import { Injectable } from '@angular/core'

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

Eine Beispielkomponente, die den Wert Ihrer globalen Variablen aktualisiert :

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

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

  constructor(private someSharedService: SomeSharedService) { }

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

Eine Beispielkomponente, die den Wert Ihrer globalen Variablen liest :

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

Beachten Sie, dass dies nicht zu Ihrer Anmerkung hinzugefügt werden providers: [ SomeSharedService ]sollte . Wenn Sie diese Zeileninjektion nicht hinzufügen, erhalten Sie immer die gleiche Instanz von . Wenn Sie die Zeile hinzufügen, wird eine frisch erstellte Instanz eingefügt.@ComponentSomeSharedService

Timo Bähr
quelle
Aber ohne die Reihe der Anbieter hinzuzufügen, bekam ich einen Fehler wie diesen:Unhandled Promise rejection: No provider for SomeSharedService
Rocky
Aha. Ich sollte providers: [SomeSharedService]in der übergeordneten Moduldatei hinzufügen . Vielen Dank.
Rocky
Dies funktioniert nicht, wenn wir Module faul laden.
lpradhap
9

Ich kenne den besten Weg nicht, aber der einfachste Weg, wenn Sie eine globale Variable innerhalb einer Komponente definieren möchten, besteht darin, eine Variable zu verwenden window, um wie folgt zu schreiben:

window.GlobalVariable = "what ever!"

Sie müssen es nicht an Bootstrap übergeben oder an andere Stellen importieren, und es ist global für alle JS zugänglich (nicht nur für Angular 2-Komponenten).

Mahdi Jadaliha
quelle
1
Ich würde sagen, es ist der schlechteste Weg. Die Verwendung einer statischen Variablen ist nicht komplizierter, aber auch nicht so hässlich ;-)
Günter Zöchbauer
2
Ich bin damit einverstanden, dass es schwierig ist, damit umzugehen. Ich habe sie jedoch nicht mehr in der Entwicklung verwendet, bis ich gefunden habe, was ich in Produktionen einbauen möchte. In statischen Variablen müssen Sie sie immer wieder importieren, wo immer Sie sie verwenden möchten. Außerdem gab es einen Fall, in dem ich meine Ansicht unterwegs mit jquery in eckigen Komponenten erstellt habe - es gab keine Vorlage und um dem statischen DOM Ereignisse hinzuzufügen, die statisch sind Variable ist Schmerz.
Mahdi Jadaliha
1
Außerdem ist es nicht statisch, Sie können den Wert von überall ändern!
Mahdi Jadaliha
1
Es zerstört auch das serverseitige Rendern. Vermeiden Sie es, das Fenster oder Dokument direkt zu manipulieren.
Erik Honn
1
Einverstanden. Aber ich persönlich folge keiner Richtlinie in meinem Leben (wenn ich es besser machen könnte).
Mahdi Jadaliha
7

So benutze ich es:

global.ts

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

um es zu benutzen, importiere es einfach so:

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
}

BEARBEITET: "_" wird wie empfohlen vorangestellt.

Guilherme Teubl
quelle
Verwenden Sie "_" nicht als Präfix für private Eigenschaften. github.com/Microsoft/TypeScript/wiki/Coding-guidelines
crh225
4

Ich denke, der beste Weg ist, ein Objekt mit globalen Variablen in Ihrer gesamten Anwendung zu teilen, indem Sie es exportieren und importieren, wo Sie wollen.

Erstellen Sie zunächst eine neue .ts- Datei, z. B. globals.ts, und deklarieren Sie ein Objekt. Ich habe ihm einen Objekttyp gegeben, aber Sie können auch einen beliebigen Typ oder {} verwenden

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

Danach importieren Sie es

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

Und benutze es

console.log(globalVariables);
0x1ad2
quelle
3

Ich mag die Antwort von @supercobra, aber ich würde das const-Schlüsselwort verwenden, da es in ES6 bereits verfügbar ist:

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

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