Смотреть несколько атрибутов $ scope

386

Есть ли способ подписаться на события на нескольких объектах, используя $watch

например.

$scope.$watch('item1, item2', function () { });
Теги:
events
angularjs-watch

10 ответов

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

Начиная с 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 
});
  • 6
    в чем разница с $ watchCollection ('[a, b]') ??
  • 24
    Разница в том, что вы можете использовать правильный массив вместо строки, которая выглядит как массив
Показать ещё 2 комментария
266

Начиная с 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
});

Пример плунжера здесь

Документация здесь

  • 107
    Обратите внимание, что первый параметр не является массивом. Это строка, которая выглядит как массив.
  • 1
    Спасибо за это. если это сработает для меня, я дам вам тысячу золотых монет - виртуальных, конечно :)
Показать ещё 3 комментария
111

$watch Первый параметр также может быть функцией.

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

Если ваши два комбинированных значения просты, первый параметр - это просто выражение angular. Например, firstName и lastName:

$scope.$watch('firstName + lastName', function() {
  //stuff
});
  • 8
    Это похоже на сценарий использования, который требует включения в платформу по умолчанию. Даже вычисляемое свойство, fullName = firstName + " " + lastName же простое, как fullName = firstName + " " + lastName требует передачи функции в качестве первого аргумента (а не простого выражения, такого как 'firstName, lastName' ). Angular настолько мощен, но есть некоторые области, где он может быть гораздо более дружественным к разработчикам способами, которые (как представляется) не ставят под угрозу производительность или принципы проектирования.
  • 4
    Ну, $ watch просто принимает угловое выражение, которое оценивается по объему вызова. Таким образом, вы можете сделать $scope.$watch('firstName + lastName', function() {...}) . Вы также можете просто сделать два наблюдения: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged); , Я добавил простой случай к ответу.
Показать ещё 4 комментария
65

Вот решение, очень похожее на ваш оригинальный псевдокод, который действительно работает:

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

EDIT: Хорошо, я думаю, что это еще лучше:

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

В основном мы пропустим шаг json, который казался глупым, но он не работал без него. Они являются часто отсутствующим 3-м параметром, который включает в себя равенство объектов, а не ссылочное равенство. Тогда сравнения между нашими созданными объектами массива действительно работают правильно.

  • 0
    У меня был похожий вопрос. И это правильный ответ для меня.
  • 0
    Оба имеют небольшое снижение производительности, если элементы в выражении массива не являются простыми типами.
Показать ещё 3 комментария
12

Почему бы просто не обернуть его в forEach?

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

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

  • 0
    В этом случае log () будет выполняться несколько раз, верно? Я думаю, что в случае вложенных функций $ watch это не так. И это не должно быть в решении для просмотра нескольких атрибутов одновременно.
  • 0
    Нет, журнал выполняется только один раз за изменение для каждого отслеживаемого свойства. Почему это будет вызвано несколько раз?
Показать ещё 4 комментария
10

Вы можете использовать функции в $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 ? Разве область не распространяется на функции без явного ее определения?
  • 1
    Я использую машинопись, представленный код является скомпилированным результатом.
9

Несколько более безопасное решение для объединения значений может заключаться в использовании следующих функций $watch:

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

или

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

как насчет:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);
  • 2
    Без третьего true параметра to to scope.$watch (как в вашем примере), listener() будет срабатывать каждый раз, потому что анонимный хеш имеет разную ссылку каждый раз.
  • 0
    Я нашел это решение сработало для моей ситуации. Для меня это было больше похоже на: return { a: functionA(), b: functionB(), ... } . Затем я проверяю возвращенные объекты новых и старых значений друг против друга.
5

$Первым параметром watch может быть angular выражение или функция. См. Документацию по $scope. $Watch. Он содержит много полезной информации о том, как работает метод $watch: когда вызывается watchExpression, как angular сравнивает результаты и т.д.

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

Здесь функция будет вызвана, когда изменится значение возраста и имени.

  • 2
    Также убедитесь, что в этом случае не используйте аргументы newValue и oldValue, которые angular передает в обратный вызов, потому что они будут являться результатом конкатенации, а не только измененным полем.

Ещё вопросы

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