Angular 4/5/6全局变量

130

我在我的Angular 2应用程序中创建全局变量方面遇到了很大的困难。

所以,我有一个名为globals.ts的文件,它看起来像这样:

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


@Injectable()
export class Globals {

  var role = 'test';

}

我希望在我的组件的HTML视图中像这样使用变量“role”:

{{ role }} 

我已经按以下方式将globals.ts文件添加到我的app.module.ts中:

providers: [
  Globals
],
无论我对这个文件做了什么,它似乎都不起作用。我不想每个组件都手动导入globals.ts文件,因此我想使用providers功能。

无论我对这个文件做了什么,它似乎都不起作用。我不想每个组件都手动导入globals.ts文件,因此我想使用提供程序功能。


4
这是一个名为Globals的类,其中包含一个名为role的变量,它的初始值是'test'。 - zerkms
这应该是我的Globals类,我想在其中存储我的全局变量。例如,变量“role”,它现在应该有一个字符串“test”,只是为了测试全局变量是否起作用。 - A E
这不是有效的 TypeScript。 - zerkms
我应该删除 "var" 吗? - A E
使用 localStorage 怎么样? - suhailvs
6个回答

195
您可以通过 Angular 依赖注入 ,从您的应用程序的任何位置访问Globals实体。如果您想在某个组件的模板中输出Globals.role值,则应像使用任何服务一样通过该组件的构造函数注入Globals
// hello.component.ts
import { Component } from '@angular/core';
import { Globals } from './globals';

@Component({
  selector: 'hello',
  template: 'The global role is {{globals.role}}',
  providers: [ Globals ] // this depends on situation, see below
})

export class HelloComponent {
  constructor(public globals: Globals) {}
}

我在HelloComponent中提供了Globals,但实际上可以在某些HelloComponent的父组件甚至是AppModule中提供。只要您的Globals仅包含无法更改的静态数据(例如常量),这不会有任何影响。但是,如果不是这样,例如不同的组件/服务可能想要更改那些数据,则Globals必须是单例。在这种情况下,它应该在层次结构的最高级别中提供,即在它将被使用的地方。假设这是AppModule

import { Globals } from './globals'

@NgModule({
  // ... imports, declarations etc
  providers: [
    // ... other global providers
    Globals // so do not provide it into another components/services if you want it to be a singleton
  ]
})

此外,你不能像你所做的那样使用 var,它应该是

// globals.ts
import { Injectable } from '@angular/core';

@Injectable()
export class Globals {
  role: string = 'test';
}

更新

最终,我在 stackblitz 上创建了一个简单的演示(链接),其中一个单一的 Globals 在 3 个组件之间进行共享,并且其中一个组件可以更改 Globals.role 的值。


2
@AtulStha,我刚把演示从Plunker转移到了Stackblitz,感谢您提出的问题。 - dhilt
1
@GauravSachdeva,你可以在SO上发布你的问题,我相信这将是最好的选择。如果你想让我看到它,请在评论中添加链接。 - dhilt
1
请问您能否解释一下,为什么您的示例比只在 GlobalConst.js 中定义所有常量更好,例如: export const customError = ['请重试']; export const myUrl = '/example';并通过导入它们在其他组件中使用: import * from './GlobalConst'; - dgraf
@dgraf 这个也可以用,我更喜欢这个而不是使用服务的那个。然而,如果正确实现,你可以在需要时重新分配服务中的值(例如新状态),但导出的常量无法被重新分配。 - knnhcn
1
它在开发模式下运行良好@dhilt,但实际上,我们无法在HTML中访问私有成员(私有全局变量:Globals),通过将“globals”设置为私有变量,它无法在HTML中访问,我们也不想将其公开。在生产模式下,构建时会出现错误。那么在这种情况下我们该怎么办呢? - Raza Ellahi
显示剩余7条评论

31

我使用环境来实现这一点。它可以自动工作,您无需创建新的可注入服务,并且对我来说最有用的是,不需要通过构造函数导入。

1)在您的environment.ts中创建环境变量。

export const environment = {
    ...
    // runtime variables
    isContentLoading: false,
    isDeployNeeded: false
}

2) 在*.ts文件中 导入environment.ts 并创建公共的 变量(例如"env"),以便在html模板中使用

import { environment } from 'environments/environment';

@Component(...)
export class TestComponent {
    ...
    env = environment;
}

3)在模板中使用它...

<app-spinner *ngIf='env.isContentLoading'></app-spinner>

在*.ts中...

env.isContentLoading = false 

在template中不需要它时,可以使用environment.isContentLoading。你可以像这样在environment.ts中创建自己的全局设置:

export const globals = {
    isContentLoading: false,
    isDeployNeeded: false
}

并直接导入这些变量(y)


3
生产环境构建时,你会把所有文件都放在两个位置吗? - Mulperi
3
这是最好的方法。@Mulperi 在environment.ts文件中创建全局变量并不是必需的。只需在应用程序目录中创建globals.ts文件,使用上述导出内容,并在需要使用这些全局变量的地方导入此文件即可。 - PrasadW
2
我同意。最近我按照@PrasadW指出的方式修改了这个解决方案。 - Martin Slavkovsky
1
新的Angular版本现在默认确实使用了这种方法。有一个environments/environment.tsenvironments/environment.prod.ts文件会自动替换。 - rugk
2
谁发明了Angular应该考虑到这种简洁性! - Jeb50

0

我在与其他JSON文件结合使用时使用环境变量,例如显示构建信息和其他内容。这样,您可以在不同的环境中混合和/或重复使用它们。

// environment.ts, environment.prod.ts
export const environment = {
  
  ...
  appName: require('../../package.json').name,
  appVersion: require('../../package.json').version,

  ...
  globalX: require('../../globals.json').X,
  globalY: require('../../globals.json').Y,      
}

使用方法:

import { environment } from './../environments/environment';

export class FooterComponent implements OnInit {

  appName = environment.appName;
  buildVersion = environment.appVersion;
  x = environment.globalX;
  y = environment.globalY;
}

0

虽然之前提到的所有答案都是正确的,但 Angular 的方式是使用管道、装饰器或组件。

如果你只想显示一个字符串,那么使用组件即可。

组件

<Role></Role>

装饰器

如果你想要做这样的事情:

<a href="/foo/{{userId}}/bar">Link</a>

你可能想要实现自己的装饰器
<a [customHref]="[/foo/:userId/bar]">Link</a>

如果您使用内置的路由器模块和routerlink,您可以简单地扩展RouterLink指令并实现您的更改。

管道

somevariable = "this is my #:userId";

{{someVariable | applyglobals}}

等等。


-1

虽然不是很推荐,但其他答案都不是真正的全局变量。要创建一个真正的全局变量,您可以这样做。

Index.html

<body>
  <app-root></app-root>
  <script>
    myTest = 1;
  </script>
</body>

在Angular中的组件或其他任何内容

...在导入之后的右上方:

declare const myTest: any;

...稍后:

console.warn(myTest); // outputs '1'

和使用window对象一样。 - Playdome.io

-2
你可以使用 Window 对象并随时访问它。 例如:window.defaultTitle = "my title"; 然后你可以在任何地方访问 window.defaultTitle,无需导入任何内容。

这就是它想要避免的。 - Scandinave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接