Bagaimana saya bisa mendeklarasikan variabel global dalam Angular 2 / Typescript? [Tutup]

164

Saya ingin beberapa variabel untuk dapat diakses di mana-mana dalam Angular 2dalam Typescriptbahasa. Bagaimana saya harus menyelesaikan ini?

supercobra
sumber
2
Jika mereka adalah variabel statis, tidak perlu menggunakan layanan. Cukup tambahkan variabel di beberapa file lalu impor di mana pun Anda membutuhkannya.
Eric Martinez
Sayangnya Angular2 memiliki pengecualian saat runtime, katanya Uncaught ReferenceError: Settings is not defined. Kelas Settingsdengan variabel statis publik diatur untuk mengekspor dan mengimpor tempat yang digunakan.
Sen Jacob
Saya tahu posting ini sudah tua dan ada banyak jawaban yang valid. Namun seperti yang disebutkan Eric. Jika nilai sederhana yang ingin Anda deklarasikan dan memiliki akses untuk melalui aplikasi Anda, Anda dapat membuat kelas dan mengekspor kelas dengan properti statis. Variabel statis dikaitkan dengan suatu kelas dan bukan turunan dari kelas tersebut. Anda dapat mengimpor kelas dan akan dapat mengakses properti dari class.directly.
De Wet Ellis

Jawaban:

195

Berikut adalah solusi yang paling sederhana w / o Serviceatau Observer:

Masukkan variabel global dalam file dan ekspor.

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

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

Untuk menggunakan global dalam file lain gunakan importpernyataan: import * as myGlobals from 'globals';

Contoh:

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

         ...

        }
    }

Terima kasih @ eric-martinez

supercobra
sumber
3
Mendapat kesalahan pada pernyataan impor. harus menggunakanimport * as globs from 'globals'
Mike M
13
Mengapa Anda menggunakan "wajib" alih-alih mengimpor dari?
Ayyash
4
Saya akan menggunakan export constalih-alih export var- Anda benar-benar ingin memastikan variabel global tidak dapat diubah
Michal Boska
1
Mengimpor seperti ini tidak berlaku lagi di TypeScript. Harap perbarui jawaban Anda. Yang benar adalah:import * as myGlobals from 'globals'
Mick
7
import * as myGlobals from './path/to/globals';
Timothy Zorn
89

Saya suka solusi dari @supercobra juga. Saya hanya ingin sedikit meningkatkannya. Jika Anda mengekspor objek yang berisi semua konstanta, Anda hanya bisa menggunakan ES6 impor modul tanpa menggunakan membutuhkan .

Saya juga menggunakan Object.freeze untuk membuat properti menjadi konstanta yang benar. Jika Anda tertarik dengan topik ini, Anda dapat membaca posting ini .

// global.ts

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

Rujuk modul menggunakan impor.

//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
sumber
ini bagi saya adalah solusi terbaik karena (1) ini adalah yang paling sederhana dengan jumlah kode paling sedikit dan (2) itu tidak mengharuskan Anda untuk Menyuntikkan beberapa layanan sangat ke setiap komponen atau tempat Anda ingin menggunakannya, juga tidak mengharuskan Anda untuk mendaftar di @NgModule. Saya tidak bisa seumur hidup mencari tahu mengapa perlu membuat Layanan Angular 2 untuk melakukan ini, tapi mungkin ada sesuatu yang saya abaikan? Saya menggunakan solusi hebat ini untuk saat ini tetapi tolong beri tahu saya mengapa jawaban yang lebih rumit di sini lebih baik?
FireDragon
8
GlobalVariable Anda bukan variabel. Yang konstan.
Priya R
@PriyaR LOL, ya, Anda benar. Saya berasumsi tujuan utama dari pertanyaan ini adalah untuk memiliki cara yang aman untuk mengakses beberapa nilai secara global, jadi saya berimprovisasi. Kalau tidak, jangan ragu untuk mengubah const ke var, Anda mendapatkan variabel Anda.
Tim Hong
Sisi bawah Object.freeze adalah bahwa nilai tidak diketik. Bagaimanapun, membungkus nilai dalam suatu kelas adalah desain yang lebih baik dari sudut pandang saya. Jadi kita harus memilih antara properti yang diketik dan konstanta yang benar.
Harps
cara mengatur GlobalVariable.BASE_API_URL di komponen lain ..?
Sunil Chaudhry
59

Layanan bersama adalah pendekatan terbaik

export class SharedService {
  globalVar:string;
}

Tetapi Anda harus sangat berhati-hati saat mendaftar untuk dapat berbagi satu contoh untuk seluruh aplikasi Anda. Anda perlu mendefinisikannya saat mendaftarkan aplikasi Anda:

bootstrap(AppComponent, [SharedService]);

tetapi tidak untuk mendefinisikannya lagi dalam providersatribut komponen Anda:

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

Kalau tidak, instance baru dari layanan Anda akan dibuat untuk komponen dan sub komponennya.

Anda dapat melihat pertanyaan ini mengenai bagaimana injeksi ketergantungan dan injektor hirarki bekerja di Angular2:

Anda dapat melihat bahwa Anda juga dapat menentukan Observableproperti di layanan untuk memberi tahu bagian dari aplikasi Anda ketika properti global Anda berubah:

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

Lihat pertanyaan ini untuk lebih jelasnya:

Thierry Templier
sumber
Tampaknya ini berbeda. Sepertinya @ Rat2000 berpikir jawaban kami salah. Saya biasanya menyerahkan keputusan ini kepada orang lain daripada hanya memberikan jawaban yang bersaing tetapi jika dia yakin jawaban kami salah maka saya pikir itu valid. Dokumen-dokumen yang dia tautkan dalam sebuah komentar untuk jawaban saya menyebutkan bahwa itu tidak disetujui tetapi saya melihat tidak ada kerugian dan argumen dalam dokumen tersebut cukup lemah. Juga cukup umum untuk menambahkan penyedia ke bootstrap. Apa tujuan argumen ini? Dan bagaimana dengan HTTP_PROVIDERSdan serupa, haruskah mereka juga tidak ditambahkan bootstrap()?
Günter Zöchbauer
2
Ya saya baru saja membaca argumen dan bagian dalam dokumen. Honnestly saya tidak benar-benar mengerti mengapa itu tidak dianjurkan dari dokter. Apakah ini cara untuk mendefinisikan pemisahan logis: apa inti spesifik Angular2 (penyedia perutean, penyedia http) saat bootstrap dan apa yang spesifik aplikasi dalam komponen aplikasi injector. Yang mengatakan kita hanya dapat memiliki satu sub injector (satu aplikasi) untuk satu root (didefinisikan saat bootstrap). Apakah saya melewatkan sesuatu? Terlebih lagi dalam dokumen tentang injector hirarkis, penyedia layanan didefinisikan dalam injector root ;-)
Thierry Templier
3
Satu-satunya argumen yang saya lihat adalah bahwa menjaga ruang lingkup sesempit mungkin dan menggunakan komponen root setidaknya secara teori sedikit lebih sempit daripada menggunakan bootstrap()tetapi dalam prakteknya itu tidak masalah. Saya pikir daftar mereka boostrap()membuat kode lebih mudah dimengerti. Komponen memiliki penyedia, arahan, templat. Saya menemukan ini kelebihan beban tanpa penyedia global terdaftar di sana juga. Karena itu saya lebih suka bootstrap().
Günter Zöchbauer
2
dan bagaimana seseorang merujuk variabel global tersebut? bahkan setelah bootstrap layanan, panggilan alert(globalVar)menghasilkan kesalahan.
phil294
Saya belum mencoba ini, tetapi Anda akan menginginkan sesuatu seperti: alert (this.SharedService.globalVar)
trees_are_great
39

Lihat misalnya Angular 2 - Implementasi layanan bersama

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

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

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

atau berikan nilai individual

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

class MyComponent {
  constructor(@Inject('myConfigValue') private myConfigValue:string) {
    console.log(myConfigValue);
  }
}
Günter Zöchbauer
sumber
Karena Angular2 beta 7 (saya pikir) Anda tidak boleh mendaftarkan layanan Anda langsung di komponen root (alias bootstrap). Namun Anda dapat menyuntikkan ada penyedia tertentu jika Anda ingin menimpa sesuatu dalam aplikasi Anda.
Mihai
1
Tidak yakin apa yang kamu maksud. Tentu saja Anda dapat mendaftarkan layanan di bootstrap(). bootstrap()dan komponen root adalah dua hal yang berbeda. Ketika Anda menelepon, bootstrap(AppComponent, [MyService])Anda mendaftar layanan boostrap()dan AppComponentmerupakan komponen root. Dokumen menyebutkan suatu tempat yang lebih disukai untuk mendaftar penyedia (layanan) dalam komponen root providers: ['MyService']tetapi saya belum menemukan argumen yang mendukung atau menentang bootstrap()atau komponen root.
Günter Zöchbauer
Anda dapat menemukan argumen Anda di bagian 2guide sudut Dependency Injection ( angular.io/docs/ts/latest/guide/dependency-injection.html ). Seperti yang mereka katakan, Anda bisa melakukannya tetapi tidak dikabulkan. Pengguna ini meminta cara terbaik untuk memasukkan sesuatu penyihir dengan jelas solusi Anda tidak benar. Hal yang sama berlaku untuk @ThierryTemplier
Mihai
1
Saya pikir kutipan yang lebih penting dari dokumen Angular adalah "Opsi penyedia bootstrap dimaksudkan untuk mengonfigurasi dan mengesampingkan layanan pra-registrasi Angular sendiri, seperti dukungan peruteannya." Saya jarang memasukkan servis ke dalam bootstrap sendiri, dan saya senang melihat dokumen sekarang menyarankan itu.
Mark Rajcok
1
jangan lupa untuk mengekspor kelas
Demodave
15

Buat kelas Globals di app / globals.ts :

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

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

Di komponen Anda:

import { Globals } from './globals';

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

Catatan : Anda dapat menambahkan penyedia layanan Globals secara langsung ke modul alih-alih komponen, dan Anda tidak perlu menambahkan sebagai penyedia ke setiap komponen dalam modul itu.

@NgModule({
    imports: [...],
    declarations: [...],
    providers: [ Globals ],
    bootstrap: [ AppComponent ]
})
export class AppModule {
}
gradosevic
sumber
Ini adalah jawaban terbaik, karena menawarkan pendekatan yang lebih portabel daripada harus menambahkan layanan ke setiap komponen di seluruh aplikasi. Terima kasih!
Vidal Quevedo
5
Kode berfungsi. Tetapi perhatikan bahwa menyuntikkan kelas Globalsdengan menambahkannya providers: [ ... ]berarti Anda tidak dapat mengubah nilai di dalam satu komponen dan kemudian meminta nilai yang diperbarui di dalam komponen kedua. Setiap kali Anda menyuntikkannya Globalsadalah contoh baru. Jika Anda ingin mengubah perilaku ini, cukup JANGAN tambahkan Globals sebagai penyedia.
Timo Bähr
hanya sebuah catatan, seharusnya@Injectable()
mast3rd3mon
11

IMHO untuk Angular2 (v2.2.3) cara terbaik adalah menambahkan layanan yang berisi variabel global dan menyuntikkan mereka ke dalam komponen tanpa providerstag di dalam @Componentanotasi. Dengan cara ini Anda dapat berbagi informasi antar komponen.

Layanan sampel yang memiliki variabel global:

import { Injectable } from '@angular/core'

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

Komponen sampel yang memperbarui nilai variabel global Anda:

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

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

  constructor(private someSharedService: SomeSharedService) { }

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

Komponen sampel yang membaca nilai variabel global Anda:

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

Perhatikan bahwa providers: [ SomeSharedService ]seharusnya tidak ditambahkan ke Anda @Componentpenjelasan. Dengan tidak menambahkan injeksi baris ini akan selalu memberi Anda contoh yang sama SomeSharedService. Jika Anda menambahkan baris, instance yang baru dibuat disuntikkan.

Timo Bähr
sumber
Tetapi tanpa menambahkan garis penyedia, saya mendapat kesalahan seperti ini:Unhandled Promise rejection: No provider for SomeSharedService
Rocky
Saya melihat. Saya harus menambahkan providers: [SomeSharedService]file modul induk. Terima kasih.
Rocky
Ini tidak berfungsi ketika kita malas memuat modul.
lpradhap
9

Saya tidak tahu cara terbaik, tetapi cara termudah jika Anda ingin mendefinisikan variabel global di dalam komponen adalah dengan menggunakan windowvariabel untuk menulis seperti ini:

window.GlobalVariable = "what ever!"

Anda tidak perlu meneruskannya ke bootstrap atau mengimpornya ke tempat lain, dan dapat diakses secara global ke semua JS (tidak hanya komponen sudut 2).

Mahdi Jadaliha
sumber
1
Saya akan mengatakan itu cara terburuk. Menggunakan variabel statis tidak lebih rumit tetapi juga tidak jelek ;-)
Günter Zöchbauer
2
Saya setuju itu membuat sulit untuk dikelola. Namun saya akhirnya menggunakannya dalam pengembangan sampai saya menemukan apa yang ingin saya masukkan ke produksi. Dalam variabel statis Anda harus mengimpornya lagi dan lagi di mana pun Anda ingin menggunakan, di samping ada kasus saya memproduksi pandangan saya saat bepergian dengan jquery di komponen sudut - tidak ada template, dan untuk menambahkan peristiwa ke DOM yang dihasilkan menggunakan statis variabelnya adalah nyeri.
Mahdi Jadaliha
1
Plus, itu tidak statis, Anda dapat mengubah nilainya dari mana saja!
Mahdi Jadaliha
1
Itu juga merusak rendering sisi server. Tinggal jauh dari memanipulasi jendela atau dokumen secara langsung.
Erik Honn
1
Sepakat. tetapi saya pribadi tidak mengikuti pedoman apa pun dalam hidup saya (jika saya bisa melakukan lebih baik dari itu).
Mahdi Jadaliha
7

Itulah cara saya menggunakannya:

global.ts

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

untuk menggunakannya impor saja seperti itu:

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
}

Diedit: Droped "_" diawali seperti yang direkomendasikan.

Guilherme Teubl
sumber
Jangan gunakan "_" sebagai awalan untuk properti pribadi. github.com/Microsoft/TypeScript/wiki/Coding-guidelines
crh225
4

Saya pikir cara terbaik adalah berbagi objek dengan variabel global di seluruh aplikasi Anda dengan mengekspor dan mengimpornya di tempat yang Anda inginkan.

Pertama buat file .ts baru misalnya globals.ts dan deklarasikan objek. Saya memberinya tipe Objek tetapi Anda juga bisa menggunakan tipe apa pun atau {}

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

Setelah itu impor saja

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

Dan gunakan itu

console.log(globalVariables);
0x1ad2
sumber
3

Saya suka jawaban @supercobra, tetapi saya akan menggunakan kata kunci const seperti di ES6 yang sudah tersedia:

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

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