如何在Angular 2 / Typescript中声明全局变量?[关闭]


164

我想一些变量来进行访问无处不在Angular 2Typescript语言。我应该如何去实现呢?


2
如果它们是静态变量,则无需使用服务。只需在某个文件中添加变量,然后将其导入您需要的任何位置即可。
埃里克·马丁内斯

不幸的是Angular2在运行时有异常,说Uncaught ReferenceError: Settings is not definedSettings具有公共静态变量的类设置为export并已在其使用位置导入。
森雅各布·

我知道这篇文章很旧,有很多有效的答案。但是就像埃里克提到的那样。如果您要声明一个简单的值并可以访问您的整个应用程序,则可以创建一个类并使用静态属性导出该类。静态变量与一个类而不是该类的实例相关联。您可以导入该类,并且可以直接从class。访问属性。
De Wet Ellis

Answers:


195

这是最简单的解决方案,Service没有/ 也没有Observer

将全局变量放在文件中,然后导出它们。

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

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

要在另一个文件中使用全局变量,请使用以下import语句: import * as myGlobals from 'globals';

例:

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

         ...

        }
    }

谢谢@ eric-martinez


3
在导入语句中出错。必须使用import * as globs from 'globals'
Mike M

13
为什么使用“ require”而不是“ from from”导入?
Ayyash

4
我会用export const,而不是export var-你真的想确保这些全局变量不能被改变
米哈尔Boska

1
这样的导入在TypeScript中不再有效。请更新您的答案。正确的是:import * as myGlobals from 'globals'
Mick

7
import * as myGlobals from './path/to/globals';
蒂莫西·佐恩

89

我也喜欢@supercobra的解决方案。我只是想稍微改善一下。如果导出包含所有常量的对象,则只需使用es6 import模块即可,而无需使用require

我还使用了Object.freeze来使属性成为真正的常数。如果您对该主题感兴趣,可以阅读这篇文章

// global.ts

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

使用导入引用模块。

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

export class HeroService {
    private baseApiUrl = GlobalVariable.BASE_API_URL;

    //... more code
}

这对我来说是最好的解决方案,因为(1)这是最简单且代码量最少的(2)它不需要您向每个要使用的组件或位置注入一些织补服务,也不是要求您在@NgModule中注册。我一辈子都无法弄清楚为什么要创建一个Angular 2 Service来做到这一点,但是也许我忽略了某些事情?我目前正在使用此出色的解决方案,但请告诉我为什么这里其他更复杂的答案更好?
FireDragon

8
您的GlobalVariable不是变量。它是一个常数。
Priya R

@PriyaR哈哈,是的,你是对的。我以为这个问题的主要目的是要有一种安全的方法来在全球范围内获取某些价值观,所以我即兴提出。否则,随时将const更改为var,就可以得到变量。
添洪

Object.freeze的缺点是未键入值。无论如何,从我的角度来看,将值包装在类中是更好的设计。因此,我们必须在类型化属性和真实常量之间进行选择。
竖琴

如何在另一个组件中设置GlobalVariable.BASE_API_URL。
苏尼尔·乔杜里

59

共享服务是最好的方法

export class SharedService {
  globalVar:string;
}

但是注册时需要非常小心,以便能够为整个应用程序共享一个实例。注册应用程序时需要定义它:

bootstrap(AppComponent, [SharedService]);

但不要在providers组件的属性中再次定义它:

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

否则,将为组件及其子组件创建服务的新实例。

您可以看一下有关Angular2中依赖项注入和分层注入器如何工作的问题:

您会注意到,还可以Observable在服务中定义属性,以在全局属性更改时通知应用程序的各个部分:

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

有关更多详细信息,请参见此问题:


似乎这是不同的。似乎@ Rat2000认为我们的答案是错误的。我通常将这个决定留给其他人,而不是给别人提供竞争性答案,但是如果他确信我们的答案是错误的,那么我认为这是有效的。他在对我的答案的评论中链接到的文档提到它已被劝阻,但我认为没有任何不利之处,并且文档中的论点相当薄弱。将提供程序添加到引导程序也很常见。无论如何,这一论点的目的是什么。并且怎么样HTTP_PROVIDERS和类似的,应该也不会被添加到bootstrap()
君特Zöchbauer

2
是的,我只是阅读了文档中的参数和部分。简而言之,我真的不明白为什么文档不建议这样做。它是定义逻辑拆分的一种方法:引导时Angular2的核心是什么(路由提供程序,http提供程序),应用程序组件注入器中的应用程序是特定的。也就是说,对于根一(引导时定义),我们只能有一个子注入器(应用一)。我会错过什么吗?此外,在有关分层注入器的文档中,服务提供者是在根注入器中定义的;-)
Thierry Templier,2016年

3
我看到的唯一论点是,保持范围尽可能狭窄,并且使用根组件至少在理论上比使用时稍微窄一点,bootstrap()但实际上并不重要。我认为列出它们boostrap()使代码更易于理解。组件具有提供程序,指令,模板。我发现这里也没有列出全球供应商,因此过载了。因此我更喜欢bootstrap()
君特Zöchbauer

2
以及如何引用这样的全局变量?即使在引导服务之后,调用也会alert(globalVar)导致错误。
phil294

我还没有尝试过,但是您会想要这样的东西:alert(this.SharedService.globalVar)
trees_are_great

39

参见例如Angular 2-共享服务的实现

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

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

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

或提供个人价值

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

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

从Angular2 beta 7(我认为)开始,您不应该直接在根组件(aka引导程序)中注册服务。但是,如果要覆盖应用程序中的某些内容,则可以在其中注入特定的提供程序。
Mihai 2016年

1
不明白你的意思。当然,您可以在中注册服务bootstrap()bootstrap()和根组件是两个不同的东西。调用时,您将bootstrap(AppComponent, [MyService])在其中注册服务,boostrap()AppComponent是根组件。文档提到某个地方,它providers: ['MyService']倾向于在根组件中注册提供程序(服务),但是我还没有发现赞成或反对bootstrap()根组件的任何论点。
君特Zöchbauer

您可以在angular2guide的“依赖关系注入”部分中找到您的参数(angular.io/docs/ts/latest/guide/dependency-injection.html)。就像他们说的那样,您可以做到,但不被推荐。这位用户正在寻求最好的方式来注入某些东西,显然您的解决方案并不重要。@ThierryTemplier
Mihai

1
我认为Angular文档中更重要的一句话是:“引导程序提供程序选项旨在配置和覆盖Angular自己的预注册服务,例如其路由支持。” 我很少自己引导服务,而我很高兴看到文档现在建议这样做。
Mark Rajcok '16

1
别忘了导出课程
Demodave

15

app / globals.ts中创建Globals类:

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

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

在您的组件中:

import { Globals } from './globals';

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

注意:您可以将Globals服务提供程序直接添加到模块中,而不是组件中,而无需将其作为提供程序添加到该模块中的每个组件中。

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

这是最好的答案,因为它提供了一种更加可移植的方法,而不必将服务添加到应用程序中的每个组件。谢谢!
Vidal Quevedo

5
该代码正在运行。但是请注意,在注入类Globals的同时添加它providers: [ ... ]意味着您不能在一个组件内更改值,然后在第二个组件内要求更新后的值。每次注入Globals时都是一个新实例。如果要更改此行为,只需添加Globals 为提供者即可。
TimoBähr17年

只是一个注释,应该是@Injectable()
mast3rd3mon '18

11

IMHO for Angular2(v2.2.3)的最佳方法是添加包含全局变量的服务,并将其注入到组件中,而组件中没有providers标签。@Component注释中。这样,您就可以在组件之间共享信息。

拥有全局变量的样本服务:

import { Injectable } from '@angular/core'

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

一个示例组件,用于更新全局变量的值:

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

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

  constructor(private someSharedService: SomeSharedService) { }

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

读取全局变量值的样本组件:

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

请注意,providers: [ SomeSharedService ]不应其添加到@Component注释中。通过不添加此行注入,将始终为您提供的相同实例SomeSharedService。如果添加该行,则将注入新创建的实例。


但是没有添加提供程序的行,我得到了这样的错误:Unhandled Promise rejection: No provider for SomeSharedService
Rocky

我懂了。我应该添加providers: [SomeSharedService]父模块文件。谢谢。
洛基

当我们延迟加载模块时,这不起作用。
lpradhap '18

9

我不知道最好的方法,但是如果要在组件内部定义全局变量,最简单的方法是使用window变量编写如下:

window.GlobalVariable = "what ever!"

您无需将其传递到引导程序或将其导入其他地方,并且所有JS(不仅是angular 2组件)都可以全局访问。


1
我会说这是最糟糕的方法。使用静态变量没有更复杂,但不是丑陋的任何;-)
君特Zöchbauer

2
我同意这很难管理。但是我最终在开发中使用了它们,直到找到想要投入生产的东西。在静态变量中,您必须一次又一次地将它们导入到要使用的任何地方,此外,还有一种情况是我正在使用角度组件中的jquery在旅途中生成视图-没有模板,并使用静态将事件添加到生成的DOM中变量是痛苦。
Mahdi Jadaliha

1
另外,它不是静态的,您可以从任何地方更改值!
Mahdi Jadaliha

1
它还会破坏服务器端渲染。远离直接操作窗口或文档。
Erik Honn

1
同意 但是我个人不遵循自己的生活准则(如果我可以做得更好)。
马赫迪(Mahdi Jadaliha),

7

我就是这样使用的:

全球

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

使用它就像这样导入:

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
}

编辑:删除“ _”作为建议的前缀。


不要将“ _”用作私有属性的前缀。github.com/Microsoft/TypeScript/wiki/Coding-guidelines
crh225 '16

4

我认为最好的方法是通过在需要的地方导出和导入对象,在整个应用程序中与全局变量共享一个对象。

首先创建一个新的.ts文件,例如globals.ts并声明一个对象。我给它提供了一个对象类型,但您也可以使用任何类型或{}

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

之后导入

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

并使用它

console.log(globalVariables);

3

我喜欢@supercobra的答案,但是我会使用const关键字,因为它已经在ES6中可用:

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

export const sep='/';
export const version: string="22.2.2"; 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.