$ watch не запускается при изменении массива
Я пытаюсь понять, почему мой $watch
не запускается. Это фрагмент из соответствующего контроллера:
$scope.$watch('tasks', function (newValue, oldValue) {
//do some stuff
//only enters here once
//newValue and oldValue are equal at that point
});
$scope.tasks = tasksService.tasks();
$scope.addTask = function (taskCreationString) {
tasksService.addTask(taskCreationString);//modifies tasks array
};
По моему мнению, tasks
явно обновляется правильно, так как у меня длина его связана так:
<span>There are {{tasks.length}} total tasks</span>
Что мне не хватает?
Ответы
Ответ 1
Попробуйте $watch('tasks.length', ...)
или $watch('tasks', function(...) { ... }, true)
.
По умолчанию $watch не проверяет равномерность объекта, а только для справки. Таким образом, $watch('tasks', ...)
всегда будет просто возвращать ту же ссылку на массив, которая не изменяется.
Обновление: Angular v1.1.4 добавляет метод $watchCollection() для обработки этого случая:
Shallow наблюдает за свойствами объекта и срабатывает всякий раз, когда изменяется какое-либо свойство (для массивов это подразумевает просмотр элементов массива, для карт объектов это означает просмотр свойств). Если обнаружено изменение, срабатывает обратный вызов listener
.
Ответ 2
Очень хороший ответ от @Mark. В дополнение к его ответу, есть одна важная функция функции $watch
, о которой вы должны знать.
С объявлением функции $watch
следующим образом:
$watch(watch_expression, listener, objectEquality)
Функция прослушивателя $watch
вызывается только тогда, когда значение из текущего выражения часов (в вашем случае это 'tasks'
), а предыдущий вызов смотреть выражение не равно. Angular сохраняет значение объекта для последующего сравнения. Из-за этого просмотр сложных параметров будет иметь невыгодную память и последствия для производительности. В основном более простое выражение выражения выглядит лучше.
Ответ 3
Я бы порекомендовал попробовать
$scope.$watch('tasks | json', ...)
Это приведет к изменению всех изменений в массиве tasks
, поскольку он сравнивает сериализованный массив как строку.
Ответ 4
Для одномерных массивов вы можете использовать $watchCollection
$scope.names = ['igor', 'matias', 'misko', 'james'];
$scope.dataCount = 4;
$scope.$watchCollection('names', function(newNames, oldNames) {
$scope.dataCount = newNames.length;
});