Глобальні змінні в AngularJS


348

У мене є проблема, коли я ініціалізую змінну на області в контролері. Потім він змінюється в іншому контролері, коли користувач входить. Ця змінна використовується для керування такими речами, як навігаційна панель і обмежує доступ до частин сайту залежно від типу користувача, тому важливо, щоб він утримував його значення. Проблема з ним полягає в тому, що контролер, який ініціалізує його, знову викликається кутовим деяким способом, а потім скидає змінну назад до її початкового значення.

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


12
Оскільки це результат №1 google: Тепер ви можете використовувати app.constant () та app.value () для створення констант та змінних, що стосуються додатків. Детальніше тут: bit.ly/1P51PED
Mróz

Відповіді:


491

У вас є 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/


141
Із кутового FAQ : навпаки, не створюйте сервіс, єдиною метою якого в житті є зберігання та повернення бітів даних.
Якоб Стоек

7
Я використовую експрес + кутове насіння Btford . Якщо я встановлю змінну на $ rootScope в Controller1 say і перейду до іншої URL-адреси (працює від Controller2 say), я можу отримати доступ до цієї змінної. Однак якщо я оновлюю сторінку на Controller2, то змінна більше не доступна в $ rootScope. Якщо я зберігаю дані користувачів під час входу, як я можу забезпечити доступ до цих даних в інших місцях навіть на оновлення сторінки?
Крейг Майлз

19
@JakobStoeck Комбінуйте це з цією відповіддю, і вам залишилося ввести дані в rootScope. Я також не думаю, що це правильно. Який кутовий спосіб зберігання та повернення глобально використовуваних бітів даних?
користувач2483724

11
Мені цікаво, які недоліки має служба, яка спеціально зберігає значення. Ізольована, вводиться лише там, де вам потрібно, і легко перевіряється. Який мінус?
Брайан

12
о боже, чому всі бояться реальних глобальних змінних, якщо ви знаєте, з чого буде складатися ваша програма, просто зробіть справжню глобальну змінну js замість надмірних ускладнень
Макс Ярі,

93

Якщо ви просто хочете зберегти значення, згідно з кутовою документацією про провайдерів , слід скористатися рецептом значення:

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

Потім використовуйте його в контролері так:

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

Те ж саме можна досягти, використовуючи Постачальник, Фабрику чи Сервіс, оскільки вони "просто синтаксичний цукор поверх рецепта постачальника", але використовуючи значення, ви досягнете бажаного за мінімального синтаксису.

Інший варіант - це використовувати $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можна оновлювати вашу інформацію ?
Блейз

@DeanOr Чи можливо зберегти оновлене значення між оновленнями сторінки? Значення стає реініціалізованим, якщо я оновлюю сторінку.
Набарун

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

1
Мені дуже подобається цей найкращий. Тепер я можу змінювати процес нарощування для розробників, сцени та продукту
jemiloii

1
Існує проста стаття, що пояснює використання констант і значень, схожих на глобальні змінні: ilikekillnerds.com/2014/11/…
RushabhG

36

Приклад 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 за те, що він це вказав
Tony Lâmpada

2
при оновленні значення $ rootScope буде порожнім.
xyonme

жорстке кодування $ rootScope.name дорівнює деякому значенню .. фактично нам потрібно його прочитати і встановити там.

25

В інтересах додати ще одну ідею до вікі-пулу, а як щодо AngularJS valueта constantмодулів? Я лише починаю використовувати їх сам, але мені здається, що це, мабуть, найкращі варіанти тут.

Примітка: станом на час написання, кутовий 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стає занадто безладним, занадто швидко.


Я вважаю модуль значення дуже корисним і стислим. особливо коли ви прив'язуєте його до змінної області $ в межах контролера, так що зміни в логіці або перегляді цього контролера пов'язані з глобальною змінною / значенням / послугою
Бен Уілер

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

8
localStorage.username = 'blah'

Якщо ви гарантовано будете користуватися сучасним браузером. Хоча знайте, ваші значення будуть перетворені на рядки.

Також корисно мати перевагу кешування між перезавантаженнями.


5
Хе, я збираюсь зберігати всі змінні через localStorage. У нас тоді навіть буде якась наполегливість! Крім того, щоб подолати обмеження рядків, збережемо .toString () функції, а потім зрівняємо її за потреби!
Шаз

як уже згадував @Shaz, у цьому є проблема стійкості
brubrówka

7

Будь-ласка, виправте мене, якщо я помиляюся, але коли вийде Angular 2.0, я не вірю, що $rootScopeвін буде поруч. Моя здогадка заснована на тому, що $scopeтакож знімається. Очевидно, що контролери все одно існуватимуть, тільки не в ng-controllerмоді. Думайте, замість цього вводити контролери в директиви. Оскільки випуск неминучий, найкраще використовувати сервіси як глобальні змінні, якщо ви хочете простіше перейти з версії 1.X на 2.0.


Я згоден, розміщення даних безпосередньо в $ rootScope суперечить цілі Angular. Виділіть трохи часу та правильно організуйте свій код, і це допоможе вам не тільки в оновлення AngularJS 2.x, але і в цілому протягом вашої розробки програми, оскільки він стає складнішим.
КаталінБерта

3
Якщо $ rootScope видалено, просто напишіть нову послугу, яка називається "$ rootScope" :)
uylmz

3

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


0

Спробуйте це, ви не змусите себе вводити $rootScopeв контролер.

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

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


0

Насправді це досить просто. (Якщо ви все одно використовуєте Angular 2+.)

Просто додайте

declare var myGlobalVarName;

Десь у верхній частині вашого компонентного файлу (наприклад, після операцій "імпорт"), і ви зможете отримати доступ до "myGlobalVarName" в будь-якому місці вашого компонента.


-2

Ви також можете зробити щось подібне ..

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

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

3
$ rootScope не визначено, коли ви використовуєте його таким чином.
Ахмад Ахмаді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.