354

我有一个问题,我在控制器的范围内初始化一个变量。然后在用户登录时在另一个控制器中进行更改。此变量用于控制导航栏等内容,并根据用户类型限制对站点部分的访问,因此保持其值很重要。它的问题是初始化它的控制器,被角度再次调用,然后将变量重置为其初始值。

我认为这不是声明和初始化全局变量的正确方法,它不是真正的全局变量,所以我的问题是正确的方法是什么,在当前版本的 Angular 中是否有任何好的例子?

4

12 回答 12

495

对于“全局”变量,您基本上有 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/

于 2012-08-13T16:54:18.647 回答
98

如果你只想存储一个值,根据关于 Providers 的 Angular 文档,你应该使用 Value 配方:

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

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

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

使用 Provider、Factory 或 Service 可以实现相同的目标,因为它们“只是提供程序配方之上的语法糖”,但使用 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 示例

于 2014-06-16T17:28:13.883 回答
37

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/

于 2013-09-01T16:30:40.800 回答
25

为了向 wiki 库添加另一个想法,但是 AngularJSvalueconstant模块呢?我自己才刚刚开始使用它们,但在我看来,这些可能是这里最好的选择。

注意:截至撰写本文时,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变得太混乱、太快了。

于 2014-12-19T19:37:18.153 回答
22
// 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>
于 2015-08-28T22:17:24.877 回答
8
localStorage.username = 'blah'

如果您保证使用现代浏览器。虽然知道你的价值观都会变成字符串。

还具有在重新加载之间缓存的便利优势。

于 2014-03-17T22:46:11.007 回答
7

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

于 2015-01-22T19:31:36.783 回答
3

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

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

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

于 2017-01-23T14:40:06.867 回答
0

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

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

于 2017-06-12T10:21:47.050 回答
0

试试这个,你不会强制注入$rootScope控制器。

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

您只能在运行块中使用它,因为配置块不会为您提供使用 $rootScope 的服务。

于 2018-06-29T06:51:52.453 回答
0

这实际上很容易。(如果您仍然使用 Angular 2+。)

只需添加

declare var myGlobalVarName;

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

于 2018-10-09T22:13:49.607 回答
-2

你也可以做这样的事情..

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

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}
于 2014-07-31T12:36:25.803 回答