57

我试图弄清楚为什么我$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

4 回答 4

138

尝试$watch('tasks.length', ...)$watch('tasks', function(...) { ... }, true)

默认情况下,$watch不检查对象是否相等,而只是作为参考。因此,$watch('tasks', ...)将始终简单地返回相同的数组引用,它不会改变。

更新: Angular v1.1.4 添加了一个$watchCollection()方法来处理这种情况:

Shallow 监视对象的属性并在任何属性更改时触发(对于数组,这意味着监视数组项,对于对象映射,这意味着监视属性)。如果检测到更改,listener则触发回调。

于 2013-03-12T14:20:28.617 回答
13

@Mark 的回答非常好。除了他的回答之外,$watch您还应该注意功能的一项重要功能。

函数声明如下$watch

$watch(watch_expression, listener, objectEquality)

仅当当前监视表达式(在您的情况下为)中的值与先前对监视表达式的调用不相等时,才调用$watch 侦听器函数。Angular 会保存对象的值以供以后比较。因此,观看复杂的选项将对内存和性能产生不利影响。基本上,手表表达式值越简单越好。'tasks'

于 2013-03-12T17:08:30.207 回答
7

我建议尝试

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

这将捕获对数组的所有更改tasks,因为它将序列化的数组作为字符串进行比较。

于 2014-01-08T05:05:17.003 回答
3

对于一维数组,您可以使用$watchCollection

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

$scope.$watchCollection('names', function(newNames, oldNames) {
  $scope.dataCount = newNames.length;
});
于 2014-10-03T10:29:10.640 回答