AngularJS中的全局变量


348

我在控制器的作用域上初始化变量时遇到问题。然后,当用户登录时,它将在另一个控制器中进行更改。此变量用于控制诸如导航栏之类的操作,并根据用户的类型来限制对网站某些部分的访问,因此保持其值很重要。它的问题在于,初始化它的控制器会再次被调用一些方法,然后将变量重置为初始值。

我认为这不是声明和初始化全局变量的正确方法,它不是真正的全局变量,所以我的问题是正确的方法是什么,并且在使用当前版本的angular时,周围是否有很好的例子?


12
由于这是Google排名第一的结果:您现在可以使用app.constant()和app.value()来创建应用范围的常量和变量。更多信息,请访问:bit.ly/1P51PED
Mroz

Answers:


491

对于“全局”变量,您基本上有2个选择:

$rootScope是所有作用域的父项,因此公开的值将在所有模板和控制器中可见。使用$rootScope非常容易,因为您可以将其简单地注入任何控制器并在此范围内更改值。它可能很方便,但存在全局变量的所有问题

服务是单例,您可以将其注入任何控制器并在控制器的作用域中公开它们的值。作为单例的服务仍然是“全局的”,但是您已经更好地控制了它们的使用和公开位置。

使用服务稍微复杂一点,但不算多,下面是一个示例:

var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
  return {
      name : 'anonymous'
  };
});

然后在控制器中:

function MyCtrl($scope, UserService) {
    $scope.name = UserService.name;
}

这是工作中的jsFiddle:http : //jsfiddle.net/pkozlowski_opensource/BRWPM/2/


141
角FAQ:反之,不创建其唯一目的在生活中对数据的存储和回位的服务。
2013年

7
我正在使用BtfordExpress + Angular种子。如果我在Controller1的$ rootScope上设置一个变量,然后移动到另一个URL(由Controller2支持),则可以访问此变量。但是,如果刷新Controller2上的页面,则该变量将不再在$ rootScope上访问。如果我在登录时保存用户数据,如何确保即使刷新页面也可以在其他位置访问此数据?
克雷格·迈尔斯

19
@JakobStoeck将此问题与这个答案结合起来,您便可以将数据放在rootScope上了。我也不认为这是对的。存储和返回全局使用的数据位的角度方式是什么?
user2483724 2014年

11
我很好奇专门用于存储值的服务的缺点。隔离,仅在需要时注入,并且易于测试。不利之处是什么?
布赖恩

12
噢,天哪,为什么每个人都担心真正的全局变量,如果您知道应用程序将包含什么,只需制作一个真正的全局js变量而不是使事情变得过于复杂
Max Yari 2015年

93

如果只想存储值,则根据Providers上Angular文档,应使用值配方:

var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x');

然后在像这样的控制器中使用它:

myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
}]);

使用提供者,工厂或服务可以实现相同的目的,因为它们“只是提供者配方之上的语法糖”,但是使用Value将以最小的语法实现您想要的结果。

另一个选择是使用$rootScope,但这并不是真正的选择,因为出于相同的原因,您不应该使用它,而不应该使用其他语言的全局变量。它建议要谨慎使用。

由于所有范围继承$rootScope,如果你有一个变量$rootScope.data是有人忘记data已经定义并创建$scope.data在一个局部范围内,你会遇到问题。


如果要修改此值并使它在所有控制器中持久存在,请使用一个对象并修改属性,请记住,Javascript是通过“引用副本”传递的:

myApp.value('clientId', { value: 'a12345654321x' });
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
    this.change = function(value) {
        clientId.value = 'something else';
    }
}];

JSFiddle示例


1
当我在一个视图上更改该值时,新值不是持久性的。怎么来的?您能否更新您的答案,让我们看看如何更新您的答案clientId
布莱斯

@DeanOr是否可以在刷新页面之间保留更新的值?如果刷新页面,该值将重新初始化。
Nabarun 2014年

您必须为此使用其他东西,例如cookie,本地存储或数据库。
院长或

1
我真的很喜欢这个。现在,我可以按构建过程为dev,stage和prod进行修改
jemiloii

1
有一篇简单的文章解释了类似于全局变量的常量和值的使用:ilikekillnerds.com/2014/11/…–
RushabhG

36

AngularJS“全局变量”示例使用$rootScope

控制器1设置全局变量:

function MyCtrl1($scope, $rootScope) {
    $rootScope.name = 'anonymous'; 
}

控制器2读取全局变量:

function MyCtrl2($scope, $rootScope) {
    $scope.name2 = $rootScope.name; 
}

这是一个工作的jsFiddle:http : //jsfiddle.net/natefriedman/3XT3F/1/


2
在隔离范围指令的视图中,这不起作用。参见jsfiddle.net/3XT3F/7。但是您可以使用$ root来解决它。参见jsfiddle.net/3XT3F/10。由于@natefaubion它指向了
托尼Lâmpada

2
刷新时,$ rootScope值将为空。
xyonme

硬编码$ rootScope.name等于一些值。实际上,我们需要阅读并在那里进行设置。

25

为了在Wiki池中添加另一个想法,但是AngularJS valueconstant模块又如何呢?我只是自己开始使用它们,但是对我来说,这些可能是这里最好的选择。

注意:在撰写本文时,Angular 1.3.7是最新的稳定版,我相信这些已添加到1.2.0中,但是尚未通过变更日志确认。

根据需要定义的数量,可能要为它们创建一个单独的文件。但是我通常在我的应用程序.config()块之前定义这些以方便访问。由于这些模块仍然是有效的模块,因此您需要依赖于依赖注入才能使用它们,但是它们被视为应用程序模块的“全局”模块。

例如:

angular.module('myApp', [])
  .value('debug', true)
  .constant('ENVIRONMENT', 'development')
  .config({...})

然后在任何控制器中:

angular.module('myApp')
  .controller('MainCtrl', function(debug, ENVIRONMENT), {
    // here you can access `debug` and `ENVIRONMENT` as straight variables
  })

从最初的问题开始,实际上听起来好像无论如何都是可变的(值)或最终的(常数)都需要静态属性。我个人的观点比什么都重要,但是我发现将运行时配置项放在$rootScope凌乱的位置上太快了。


我发现值模块非常有用且简洁。特别是当您将其绑定到控制器内的$ scope变量时,以便将该控制器的逻辑或视图内的更改绑定到全局变量/值/服务
Ben Wheeler 2015年

20
// app.js or break it up into seperate files
// whatever structure is your flavor    
angular.module('myApp', [])    

.constant('CONFIG', {
    'APP_NAME' : 'My Awesome App',
    'APP_VERSION' : '0.0.0',
    'GOOGLE_ANALYTICS_ID' : '',
    'BASE_URL' : '',
    'SYSTEM_LANGUAGE' : ''
})

.controller('GlobalVarController', ['$scope', 'CONFIG', function($scope, CONFIG) {

    // If you wish to show the CONFIG vars in the console:
    console.log(CONFIG);

    // And your CONFIG vars in .constant will be passed to the HTML doc with this:
    $scope.config = CONFIG;
}]);

在您的HTML中:

<span ng-controller="GlobalVarController">{{config.APP_NAME}} | v{{config.APP_VERSION}}</span>

8
localStorage.username = 'blah'

如果可以保证您使用的是现代浏览器。虽然知道您的值都将变成字符串。

还具有在重新加载之间进行缓存的便捷好处。


5
嘿,我将通过localStorage存储所有变量。那我们甚至会有某种持久性!另外,为了解决字符串限制,让我们存储函数的.toString(),然后在需要时进行评估!
沙兹

已经@Shaz提到的一样,这有持续性的问题
朱波罗卡

7

如果我错了,请纠正我,但是当Angular 2.0发布时,我不相信$rootScope会出现。我的推测是基于一个事实,即$scope也将其删除。显然,控制器仍然会存在,只是不以ng-controller时尚的方式存在,请考虑将控制器注入指令中。随着即将发布的版本,如果希望更轻松地从版本1.X切换到2.0,最好将服务用作全局变量。


我同意,将数据直接放入$ rootScope违反了Angular的全部目的。花一些时间并适当地组织代码,这不仅会在AngularJS 2.x升级中为您提供帮助,而且随着应用程序变得越来越复杂,通常也会对您有所帮助。
CatalinBerta'3

3
如果$ rootScope被删除,则只需编写一个名为“ $ rootScope”的新服务即可:)
uylmz 2016年

3

您还可以使用环境变量,$window以便可以在控制器内部检查控制器外部的全局变量声明。$watch

var initWatch = function($scope,$window){
    $scope.$watch(function(scope) { return $window.globalVar },
        function(newValue) {
            $scope.updateDisplayedVar(newValue);
    });
}

请注意,使用这些全局值的摘要周期会更长,因此它并不总是实时更新的。我需要使用此配置来调查摘要时间。


0

我只是错误地找到了另一种方法:

我所做的就是声明一个var db = null上面的应用程序声明,然后app.js在我访问它时对其进行了修改,我可以controller.js 毫无问题地访问它。这种方法可能存在一些我不知道的问题,但是我猜这是一个很好的解决方案。


0

尝试此操作,您将不会强制注入$rootScope控制器。

app.run(function($rootScope) {
    $rootScope.Currency = 'USD';
});

您只能在run块中使用它,因为config块不会为您提供$ rootScope服务的使用。


0

实际上很简单。(如果您仍在使用Angular 2+。)

只需添加

declare var myGlobalVarName;

在组件文件顶部的某个位置(例如,在“ import”语句之后),您将可以在组件内部的任何位置访问“ myGlobalVarName”。


-2

您也可以做这样的事..

function MyCtrl1($scope) {
    $rootScope.$root.name = 'anonymous'; 
}

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}

3
以这种方式使用$ rootScope时未定义。
艾哈迈德·艾哈迈迪
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.