Глобальные переменные в AngularJS

У меня проблема, когда я инициализирую переменную в области в контроллере. Затем он изменяется в другом контроллере, когда пользователь входит в систему. Эта переменная используется для управления такими вещами, как панель навигации и ограничивает доступ к частям сайта в зависимости от типа пользователя, поэтому важно, чтобы она сохраняла свое значение. Проблема в том, что контроллер, который инициализирует его, снова вызывается angular some how, а затем сбрасывает переменную до ее начального значения.

Я предполагаю, что это не правильный способ объявления и инициализации глобальных переменных, ну, его не совсем глобальный, поэтому мой вопрос в том, каков правильный способ и есть ли хорошие примеры вокруг этой работы с текущей версией angular?

12 ответов


у вас есть в основном 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/


если вы просто хотите сохранить значение, в соответствии с угловая документация на провайдеров, вы должны использовать рецепт значение:

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


пример 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/


в интересах добавления другой идеи в пул Вики, но как насчет 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>

пожалуйста, поправьте меня, если я ошибаюсь, но когда Angular 2.0 выпущен, я не верю$rootScope будет вокруг. Мое предположение основано на том, что $scope также удаляется. Очевидно, что контроллеры все равно будут существовать, только не в ng-controller моды.Вместо этого подумайте о введении контроллеров в директивы. Поскольку выпуск неизбежен, лучше всего использовать службы в качестве глобальных переменных, если вы хотите более простое время для переключения с verison 1.X до 2.0.


localStorage.username = 'blah'

Если вы гарантированно находитесь в современном браузере. Хотя знайте, что все ваши ценности будут превращены в строки.

также имеет удобное преимущество кэширования между перезагрузками.


вы также можете использовать переменную среды $window чтобы глобальная переменная объявлялась вне контроллера, можно было проверить внутри $watch

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

Becareful, цикл дайджеста длиннее с этими глобальными значениями, поэтому он не всегда обновляется в режиме реального времени. Мне нужно исследовать это время дайджеста с этой конфигурацией.


Я просто нашел другой метод по ошибке:

что я сделал, так это объявил var db = null выше объявления приложения, а затем изменил его в app.js затем, когда я получил доступ к нему в controller.js Я смог получить к нему доступ без каких-либо проблем.Могут быть некоторые проблемы с этим методом, о которых я не знаю, но это хорошее решение, я думаю.


попробуйте это, вы не будете заставлять вводить $rootScope в контроллер.

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

вы можете использовать его только в блоке run, потому что блок config не предоставит вам использовать службу $rootScope.


Это на самом деле довольно легко. (Если вы используете Angular 2+ в любом случае.)

просто добавить

declare var myGlobalVarName;

где-то в верхней части вашего файла компонента (например, после операторов "import"), и вы сможете получить доступ к "myGlobalVarName" в любом месте вашего компонента.


вы также можете сделать что-то подобное ..

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

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