2013-03-12 59 views
52

我试图找出为什么我的$watch未被触发。这是从相关的控制器的一个片段:

<span>There are {{tasks.length}} total tasks</span> 

我缺少什么:

$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显然被正确,因为我已经其长度必然像这样更新?

+0

这似乎是这个问题也适用于观看的对象。相反,你必须看一个特定的财产。 – VSO 2016-05-27 23:43:50

回答

131

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

默认情况下,$watch不检查对象相等性,但仅供参考。所以,$watch('tasks', ...)将总是简单地返回相同的数组引用,这是不变的。

更新:角V1.1.4添加$watchCollection()方法来处理这种情况:

浅手表的对象和火灾的属性,只要任何性质的改变(对于阵列,这意味着观看阵列项目,对于这意味着观看属性的对象地图)。如果检测到更改,则会触发listener回调。

+0

感谢您的解释,我花了一小时不知道这 – asumaran 2014-05-07 20:08:22

+3

这缓解了很多痛苦和悲伤,谢谢! – 2014-09-02 19:21:17

+0

谢谢。今天帮助我 – VeteranLK 2017-02-21 08:10:39

13

非常好的回答@Mark。除了他的回答,还有一个重要的功能$watch你应该知道。

随着$watch函数声明如下:

$watch(watch_expression, listener, objectEquality) 

$watch监听函数被调用,只有当从当前监视表达式值(在你的情况下,它是'tasks'),以前的呼叫到手表表情不相等。 Angular保存对象的值以供以后比较。因此,观看复杂的选项将会产生不利的记忆和性能影响。基本上更简单的手表表示值越好。

+5

+1。我会提到(为了完整性),监听器函数在初始化时也被调用来初始化监视器。如果'watch_expression'没有改变,这需要发生。 – 2013-03-12 21:01:05

+0

是的...复制文档。 https://docs.angularjs.org/api/ng/type/$rootScope.Scope – hupseb 2014-07-08 13:13:32

5

我会建议您尝试

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

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

+3

作为一种警示,此解决方案将涉及在每个摘要循环中序列化为JSON,对性能来说不是太好(特别是如果对象是复杂一个或长阵列)。它*会*起作用,但它有点像一把'大锤',用来打破坚果。 – decates 2014-04-22 12:57:21

+0

对不同对象大小的小性能测试会很有趣。 – abimelex 2014-10-03 10:31:16

+0

这使我在正确的道路上解决与对象相同的问题。 – VSO 2016-05-27 23:44:22

2

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

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

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