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

что я упустил?

4 54

4 ответа:

попробовать $watch('tasks.length', ...) или $watch('tasks', function(...) { ... }, true).

по умолчанию $ watch не проверяет равенство объектов, а только для справки. Итак,$watch('tasks', ...) всегда будет просто возвращать ту же ссылку на массив, которая не меняется.

обновление: угловой v1.1. 4 добавляет a $watchCollection() метод для обработки этого случая:

Shallow наблюдает за свойствами объекта и срабатывает всякий раз, когда любое из свойств изменяется (для массивов это подразумевает наблюдение за элементами массива, для карт объектов это подразумевает наблюдение за свойствами). Если обнаружено изменение listener обратный вызов срабатывает.

очень хороший ответ от @Mark. В дополнение к его ответу, есть один важный функционал $watch функция, о которой вы должны знать.

С $watch объявление функции выглядит следующим образом:

$watch(watch_expression, listener, objectEquality)

The $watchслушатель функция вызывается только тогда, когда значение из текущего посмотреть выражение (в вашем случае это 'tasks') и предыдущий вызов посмотреть выражение не равны. Угловой сохраняет значение объекта для последующего сравнения. Из-за этого просмотр сложных опций будет иметь неблагоприятные последствия для памяти и производительности. В основном проще посмотреть выражение значение, тем лучше.

Я бы рекомендовал пробовать

$scope.$watch('tasks | json', ...)

что будет ловить все изменения tasks массив, как он сравнивает сериализованный массив как строку.

для одномерных массивов, вы можете использовать $watchCollection

$scope.names = ['igor', 'matias', 'misko', 'james'];
$scope.dataCount = 4;

$scope.$watchCollection('names', function(newNames, oldNames) {
  $scope.dataCount = newNames.length;
});