Перегляньте кілька атрибутів $ range


Відповіді:


586

Починаючи з AngularJS 1.3 з'явився новий метод, який вимагається $watchGroupспостерігати за набором виразів.

$scope.foo = 'foo';
$scope.bar = 'bar';

$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
  // newValues array contains the current values of the watch expressions
  // with the indexes matching those of the watchExpression array
  // i.e.
  // newValues[0] -> $scope.foo 
  // and 
  // newValues[1] -> $scope.bar 
});

7
яка різниця проти $ watchCollection ('[a, b]') ??
Каміль Томшик

28
Різниця полягає в тому, що ви можете використовувати правильний масив замість рядка, схожого на масив
Paolo Moretti

2
У мене була подібна проблема, але з використанням шаблону контролера. У моєму випадку виправлення полягало в тому, що додавати до змінних ім'я контролера:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels

1
Здається, це не працює для мене на Angular 1.6. Якщо я поклав на функцію журнал консолі, я можу побачити, що він просто працює один раз з newValuesі oldValuesяк undefined, під час індивідуального перегляду властивостей працює як завжди.
Алехандро Гарсія Іглесіас

290

Починаючи з AngularJS 1.1.4 ви можете використовувати $watchCollection:

$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
    // do stuff here
    // newValues and oldValues contain the new and respectively old value
    // of the observed collection array
});

Приклад Plunker тут

Документація тут


109
Зауважте, що перший параметр - це не масив. Це рядок, схожий на масив.
МК Сафі

1
спасибі за це. якщо це працює для мене, я дам тобі тисячу золотих монет - віртуальних, звичайно :)
AdityaSaxena

5
Щоб було зрозуміло (мені знадобилося кілька хвилин, щоб зрозуміти) $watchCollection, призначений передати об'єкт і забезпечити перегляд змін будь-яких властивостей об'єкта, тоді $watchGroupяк призначений набір масиву окремих властивостей, щоб слідкувати за змінами. Трохи по-різному вирішувати подібні, але різні проблеми. Фу!
Mattygabe

1
Так чи інакше новіValues ​​та oldValues ​​завжди рівні, коли ви використовуєте цей метод: plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
mostruash

Дякую. Це вирішило мою проблему. Чи є якісь хіти / проблеми щодо використання $ watch?
Syed Nasir Abbas

118

$watch Перший параметр також може бути функцією.

$scope.$watch(function watchBothItems() {
  return itemsCombinedValue();
}, function whenItemsChange() {
  //stuff
});

Якщо ваші два комбіновані значення прості, перший параметр - це просто кутове вираження, як правило. Наприклад, firstName та lastName:

$scope.$watch('firstName + lastName', function() {
  //stuff
});

8
Це здається випадком використання, який за замовчуванням плаче за включенням у рамки. Навіть обчислена властивість настільки проста, як fullName = firstName + " " + lastNameвимагає передачі функції в якості першого аргументу (а не простого виразу, як 'firstName, lastName'). Кутовий настільки потужний, але є деякі сфери, де це може бути набагато більш зручним для розробників способами, які не (здаються) компрометують продуктивність або принципи дизайну.
XML

4
Ну $ watch просто приймає кутове вираження, яке оцінюється за сферою, на яку він викликається. Так ви могли зробити $scope.$watch('firstName + lastName', function() {...}). Ви можете просто зробити два годинник: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);. Я відповів простим випадком до відповіді.
Ендрю Джослін

Плюс у 'firstName + lastName' - це об'єднання рядків. Тож угловий просто перевіряє, чи зараз результат конкатенації відрізняється.
mb21

16
Зв'язування рядків вимагає трохи обережності - якщо ви зміните "пара-орман" на "пара-норман", ви не викликаєте відповідь; найкраще поставити роздільник на зразок "\ t | \ t" між першим і другим термінами, або просто дотримуватися JSON, який є остаточним
Дейв Едельхарт

хоча amberjs смокче, але він має цю особливість нарощувати! чути, що кутові хлопці. Я думаю, що робити годинник - це найбільш раціональний спосіб.
Аладдін Мхемед

70

Ось рішення, дуже схоже на ваш оригінальний псевдо-код, який насправді працює:

$scope.$watch('[item1, item2] | json', function () { });

EDIT: Гаразд, я думаю, це ще краще:

$scope.$watch('[item1, item2]', function () { }, true);

В основному ми пропускаємо крок json, який, здавалося, почав робитись німим, але без нього не вийшло. Ключовим моментом є часто опущений 3-й параметр, який вмикає рівність об'єкта на відміну від еталонної рівності. Тоді порівняння між створеними нами об’єктами масиву насправді працюють правильно.


У мене було подібне питання. І це правильна відповідь для мене.
Келвін Ченг

Обидва мають невелику накладну ефективність, якщо елементи в виразі масиву не прості типи.
null

Це правда .. це робить повне порівняння глибини компонентів об'єктів. Що може бути, а може і не бути тим, що ви хочете. Дивіться ухвалений на даний момент відповідь на версію, використовуючи сучасний кутовий, який не проводить повного порівняння глибини.
Karen Zilles

Чомусь, коли я намагався використовувати $ watchCollection через масив, я отримав цю помилку, TypeError: Object #<Object> has no method '$watchCollection'але це рішення допомагає мені вирішити свою проблему!
abottoni

Класно, ви навіть можете переглядати значення в об'єктах:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Серж ван ден Овер

15

Ви можете використовувати функції в $ watchGroup для вибору полів об'єкта в області застосування.

        $scope.$watchGroup(
        [function () { return _this.$scope.ViewModel.Monitor1Scale; },   
         function () { return _this.$scope.ViewModel.Monitor2Scale; }],  
         function (newVal, oldVal, scope) 
         {
             if (newVal != oldVal) {
                 _this.updateMonitorScales();
             }
         });

1
Для чого ви використовуєте _this? Хіба сфера не переноситься на функції, не чітко визначаючи її?
sg.cc

1
Я використовую машинопис, представлений код складається за результатами.
Ян Чжан

12

Чому б просто не загорнути його в forEach?

angular.forEach(['a', 'b', 'c'], function (key) {
  scope.$watch(key, function (v) {
    changed();
  });
});

Це приблизно такий самий накладні витрати, як надання функції для комбінованого значення, без насправді турбуватися про склад значення .


У цьому випадку журнал () виконується кілька разів, правда? Я думаю, що у разі вкладених функцій $ watch це не стане. І це не повинно бути в рішенні для перегляду відразу декількох атрибутів.
Джон Доу

Ні, журнал виконується лише один раз за зміну за переглянуту властивість. Чому б його викликали кілька разів?
Ерік Айгнер

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

1
Звісно, ​​чому б ні? Я роблю це так у своєму проекті. changed()викликається, коли щось змінюється в будь-якому з властивостей. Це точно така ж поведінка, як якщо б була надана функція для комбінованого значення.
Ерік Егнер

1
Трохи інакше, що якщо кілька елементів у масиві змінюються одночасно, $ watch запустить обробник лише один раз, а не один раз за змінений елемент.
бінглі

11

Трохи безпечнішим рішенням для об'єднання значень може бути використання в якості своєї $watchфункції наступного :

function() { return angular.toJson([item1, item2]) }

або

$scope.$watch(
  function() {
    return angular.toJson([item1, item2]);
  },
  function() {
    // Stuff to do after either value changes
  });

5

Перший параметр $ watch може бути кутовим виразом або функцією. Дивіться документацію про $ range. $ Watch . Він містить багато корисної інформації про те, як працює метод $ watch: коли виклик watchExpression, як кутовий порівняння результатів тощо.


4

як щодо:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);

2
Без третього trueпараметра до scope.$watch(як у вашому прикладі), listener()він запускатиметься кожного разу, оскільки анонімний хеш має кожен раз різні посилання.
Петро В. Морч

Я виявив, що це рішення працює для моєї ситуації. Для мене це було більше схоже на : return { a: functionA(), b: functionB(), ... }. Потім я перевіряю повернені об'єкти нових і старих значень один проти одного.
RevNoah

4
$scope.$watch('age + name', function () {
  //called when name or age changed
});

Тут функція буде викликана, коли зміниться і вік, і значення імені.


2
Також будьте впевнені, що в цьому випадку не використовуйте аргументи newValue та oldValue, що кутовий переходить у зворотний виклик, тому що вони будуть результатом конкатенації, а не лише полем, яке було змінено
Акаш Шінде

1

Кутовий, представлений $watchGroupу версії 1.3, за допомогою якого ми можемо спостерігати кілька змінних, за допомогою одного $watchGroupблоку $watchGroupмасив приймає масив як перший параметр, в який ми можемо включити всі наші змінні для перегляду.

$scope.$watchGroup(['var1','var2'],function(newVals,oldVals){
   console.log("new value of var1 = " newVals[0]);
   console.log("new value of var2 = " newVals[1]);
   console.log("old value of var1 = " oldVals[0]);
   console.log("old value of var2 = " oldVals[1]);
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.