AngularJS中的全局变量
我有一个问题,我在一个控制器的范围初始化一个变量。 然后在用户登录时在另一个控制器中进行更改。此变量用于控制导航栏等内容,并根据用户的类型限制对站点部分的访问,因此重要的是它保留其值。 问题在于,初始化它的控制器被角度再次调用,然后将该变量重置为其初始值。
我认为这不是正确的方式来声明和初始化全局变量,以及它不是真正的全球性,所以我的问题是什么是正确的方式,是否有任何与目前版本的角度工作的好例子?
你基本上有2个“全局”变量的选项:
- 使用
$rootScope
http://docs.angularjs.org/api/ng.$rootScope - 使用服务http://docs.angularjs.org/guide/services
$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/
如果你只是想存储一个值,根据供应商的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示例
使用$rootScope
的AngularJS“全局变量”示例:
控制器1设置全局变量:
function MyCtrl1($scope, $rootScope) { $rootScope.name = 'anonymous'; }
控制器2读取全局变量:
function MyCtrl2($scope, $rootScope) { $scope.name2 = $rootScope.name; }
这里是一个工作jsFiddle: http : //jsfiddle.net/natefriedman/3XT3F/1/
为了给wiki池添加另一个想法,但AngularJS的value
和constant
模块呢? 我只是开始自己使用它们,但这听起来像这些可能是最好的选择。
注意:截至写作时,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
太乱了,太快了。
// 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>
localStorage.username = 'blah'
如果你保证在现代浏览器。 虽然知道你的价值将全部变成弦乐。
在重装之间也有缓存的好处。
请纠正我,如果我错了,但是当Angular 2.0发布时,我不相信$rootScope
会在附近。 我的猜想是基于$scope
被删除的事实。 显然控制器,仍然存在,只是不是在ng-controller
时尚。认为注入控制器到指令,而不是。 随着发布即将到来,如果您希望更容易地从verison 1.X切换到2.0,最好将服务用作全局变量。
您还可以使用环境变量$window
以便在$watch
内部检查在控制器外部声明的全局变量
var initWatch = function($scope,$window){ $scope.$watch(function(scope) { return $window.globalVar }, function(newValue) { $scope.updateDisplayedVar(newValue); }); }
另外,这些全局值的摘要周期更长,所以并不总是实时更新的。 我需要用这个配置来调查摘要时间。
我刚刚发现了另一种方法:
我所做的是声明var db = null
上面的应用程序声明,然后在app.js
修改它,然后当我在controller.js
访问它,我可以访问它没有任何问题。这可能会有一些问题方法,我不知道,但这是一个很好的解决方案,我猜。
你也可以做这样的事情
function MyCtrl1($scope) { $rootScope.$root.name = 'anonymous'; } function MyCtrl2($scope) { var name = $rootScope.$root.name; }