AngularJS: $часы не запускаются для изменения массива объектов
У меня есть таблица, и пользователь может выбрать фильтрацию строк в таблице на основе определенных столбцов и определенных значений для этих столбцов. Структура объекта для отслеживания этого фильтра выглядит следующим образом:
$scope.activeFilterAttributes = [
{
"columnName": "city",
"values": ["LA", "OT", "NY"]
},
{
"columnName": "weather",
"values": ["humid", "sunny"]
}
];
Таким образом, объекты в массиве содержат ключи "columnName" и "values". "columnName" означает столбец для фильтра, а "значения" - значения фильтра. В основном, вышеупомянутый массив приведет к строкам в таблице, для которых в столбце города содержатся значения "LA", "OT" или "NY" в качестве значений, а погодный столбец содержит "влажный" или "солнечный" в качестве значений. Другие строки, которые не содержат этих значений, не отображаются.
Чтобы лучше понять этот объект, если пользователь хочет видеть только те строки, у которых есть "LA" или "NY" в столбце "city", результирующий массив будет выглядеть так:
$scope.activeFilterAttributes = [
{
"columnName": "city",
"values": ["LA", "NY"]
},
{
"columnName": "weather",
"values": []
}
];
Пользователь устанавливает или удаляет эти фильтры. Всякий раз, когда это происходит, этот массив обновляется.
Это обновление происходит правильно, и я проверил его - здесь нет проблем.
Проблема заключается в $watch(). У меня есть следующий код:
$scope.$watch('activeFilterAttributes', function() {
//Code that should update the rows displayed in the table based on the filter
}}
В то время как $scope.activeFilterAttributes
обновляется должным образом, и когда пользователь обновил фильтр в пользовательском интерфейсе, $watch не запускается, когда он обновляется. Он запускается в первый раз, когда приложение загружается, но будущие обновления не влияют на это.
Я создал скрипку, чтобы продемонстрировать это: http://jsfiddle.net/nCHQV/
В скрипке $scope.info
представляет собой строки таблицы, так сказать.
$scope.data
представляет фильтр.
Нажатие на кнопку эквивалентно обновлению фильтра (в случае скрипта - данных) и, таким образом, обновлению строк, отображаемых в таблице (в случае скрипта - информация). Но, как видно, информация не обновляется при нажатии кнопки.
Не следует ли срабатывать $scope.$watch
при изменении массива объектов?
Ответы
Ответ 1
Метод $watch
принимает необязательный третий параметр с именем objectEquality
, который проверяет, что оба объекта равны, а не просто используют одну и ту же ссылку. Это не поведение по умолчанию, потому что это более дорогая операция, чем контрольная проверка. Ваши часы не запускаются, потому что они все еще относятся к одному и тому же объекту.
Подробнее см. docs.
$scope.$watch('activeFilterAttributes', function() {
// ...
}, true); // <-- objectEquality
Добавьте этот параметр и все хорошо.
Ответ 2
Принятый ответ немного устарел, как и в случае с AngularJS 1.1.4, функция $WatchCollection
была добавлена для использования с массивами и другими коллекциями, что намного дешевле, чем $Watch
с установленным флагом глубокого равенства к true.
Таким образом, эта новая функция теперь предпочтительнее в большинстве ситуаций.
См. в этой статье для более подробных различий между $Watch
функциями