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

318

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

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

  • 12
    Поскольку это # 1 результат Google: теперь вы можете использовать app.constant () и app.value () для создания констант и переменных для всего приложения. Больше здесь: bit.ly/1P51PED
Теги:
global-variables

10 ответов

431
Лучший ответ

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

  • 138
    Из Angular FAQ : наоборот, не создавайте сервис, единственная цель которого в жизни - хранить и возвращать биты данных.
  • 7
    Я использую семя Express + Angular от Btford . Если я установлю переменную в $ rootScope в Controller1 скажем и перейду на другой URL (питание от Controller2 скажем), я получу доступ к этой переменной. Однако, если я обновлю страницу на Controller2, переменная больше не будет доступна в $ rootScope. Если я сохраняю данные пользователя при входе в систему, как я могу гарантировать, что эти данные доступны в другом месте даже при обновлении страницы?
Показать ещё 16 комментариев
81

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

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

Затем используйте его в контроллере следующим образом:

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

То же самое можно достичь с помощью Провайдера, Factory или Service, поскольку они являются "просто синтаксическим сахаром поверх рецепта поставщика", но использование значения достигнет того, чего вы хотите с минимальным синтаксисом.

Другой вариант - использовать $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 ?
  • 0
    @DeanOr Можно ли сохранить обновленное значение между обновлениями страницы? Значение будет повторно инициализировано, если я обновлю страницу.
Показать ещё 4 комментария
29

Пример глобальных переменных 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 за указание на это
  • 2
    при обновлении значение $ rootScope будет пустым.
Показать ещё 1 комментарий
21

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

Из исходного вопроса на самом деле звучит так, как будто здесь требуются статические свойства, либо как изменяемые (значения), либо final (constant). Это больше мое личное мнение, чем что-либо еще, но я считаю, что размещение элементов конфигурации времени выполнения на $rootScope слишком запутанно, слишком быстро.

  • 0
    Я считаю модуль стоимости очень полезным и лаконичным. особенно когда вы связываете его с переменной $ scope внутри контроллера, чтобы изменения в логике или представлении этого контроллера были связаны с глобальной переменной / значением / сервисом
16
// 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>
7
localStorage.username = 'blah'

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

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

  • 5
    Хех, я собираюсь хранить все переменные через localStorage. Тогда у нас даже будет какая-то настойчивость! Кроме того, чтобы обойти ограничение строки, давайте сохраним функцию .toString () функции, а затем оценим ее при необходимости!
  • 0
    как уже упоминалось @Shaz, это проблема постоянства
5

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

  • 0
    Я согласен, размещение данных непосредственно в $ rootScope противоречит всей цели Angular. Потратьте немного времени и правильно упорядочите код, и он поможет вам не только в обновлении AngularJS 2.x, но и в целом в процессе разработки вашего приложения по мере его усложнения.
  • 3
    Если $ rootScope удален, просто напишите новый сервис, который называется «$ rootScope» :)
1

Вы также можете использовать переменную окружения $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 Я смог получить к нему доступ без каких-либо проблем. Возможно, некоторые проблемы с этим методом, о которых я не знаю, но это хорошее решение, я думаю.

-1

Вы также можете сделать что-то вроде этого.

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

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}
  • 3
    $ rootScope не определен, когда вы используете его таким образом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню