我在控制器中初始化作用域上的变量时遇到了问题。然后,当用户登录时,它会在另一个控制器中更改。此变量用于控制导航栏等内容,并根据用户类型限制对站点部分的访问,因此保持其值很重要。它的问题在于初始化它的控制器被角度再次调用,然后将变量重置回其初始值。
我认为这不是声明和初始化全局变量的正确方法,好吧,它不是真正的全局方法,所以我的问题是什么是正确的方法,是否有任何关于当前版本的 angular 工作的好例子?
对于"全局"变量,您基本上有 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 文档,你应该使用 Value 配方:
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
中访问它时我能够毫无问题地访问它。这种方法可能存在一些我不知道的问题,但我想这是一个很好的解决方案。
试试这个,你不会强制在控制器中注入$rootScope
。
app.run(function($rootScope) {
$rootScope.Currency = 'USD';
});
您只能在运行块中使用它,因为配置块不会为您提供使用$rootScope的服务。
这实际上很容易。(如果你使用的是 Angular 2+。
只需添加
declare var myGlobalVarName;
在组件文件顶部的某个位置(例如在"import"语句之后),您将能够访问组件内任何位置的"myGlobalVarName"。
你也可以做这样的事情..
function MyCtrl1($scope) {
$rootScope.$root.name = 'anonymous';
}
function MyCtrl2($scope) {
var name = $rootScope.$root.name;
}