Глобальные переменные в 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;
}