Подтвердить что ты не робот

$ 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>

Что мне не хватает?

4b9b3361

Ответ 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;
});