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

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

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

Ответ 1

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

Ответ 2

Если вы просто хотите сохранить значение, согласно документации 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

Ответ 3

Пример глобальных переменных 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/

Ответ 4

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

Ответ 5

// 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>

Ответ 6

localStorage.username = 'blah'

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

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

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

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

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

Ответ 10

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

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

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

Ответ 11

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

Просто добавь

declare var myGlobalVarName;

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

Ответ 12

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

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

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