AngularJS:$ watch未被触发更改对象数组

时间:2013-03-30 17:21:35

标签: angularjs

我有一个表,用户可以根据这些列的某些列和某些值来选择过滤表中的行。跟踪此过滤器的对象结构如下所示:

$scope.activeFilterAttributes = [
    {
        "columnName": "city",
        "values": ["LA", "OT", "NY"]
    },
    {
        "columnName": "weather",
        "values": ["humid", "sunny"]
    }
];

因此,数组中的对象包含“columnName”和“values”键。 “columnName”表示要为过滤器考虑的列,而“values”包含过滤器值。基本上,上面的数组将导致表中的行,其中city列包含“LA”,“OT”或“NY”作为值,而weather列包含“湿”或“晴天”作为值。不显示不包含这些值的其他行。

为了更好地理解这个对象,如果用户只希望在“city”列中看到那些“LA”或“NY”的行,则结果数组将如下所示:

$scope.activeFilterAttributes = [
    {
        "columnName": "city",
        "values": ["LA", "NY"]
    },
    {
        "columnName": "weather",
        "values": []
    }
];

用户设置或删除这些过滤器。只要发生这种情况,就会更新上面的数组。 此更新正确发生,我已经验证了 - 这里没问题。

问题出在$ watch()上。我有以下代码:

$scope.$watch('activeFilterAttributes', function() {
    //Code that should update the rows displayed in the table based on the filter
}}

当用户在UI中更新过滤器时,$scope.activeFilterAttributes已正确更新,但更新时不会触发$ watch。它是在应用程序加载时第一次触发,但未来的更新对此没有影响。

我创造了一个小提琴来证明这一点:http://jsfiddle.net/nCHQV/

在小提琴中,$scope.info表示表格的行,可以这么说;
$scope.data代表过滤器 单击该按钮相当于更新过滤器(在小提琴的情况下 - 数据),从而更新表中显示的行(在小提琴的情况下 - 信息)。但是可以看出,单击按钮时信息不会更新。

当对象数组发生变化时,不应该触发$scope.$watch吗?

2 个答案:

答案 0 :(得分:66)

$watch方法使用一个名为objectEquality的可选第三个参数来检查两个对象是否相等,而不是仅共享相同的引用。这不是默认行为,因为它比参考检查更昂贵。您的手表未被触发,因为它仍然指向同一个物体。

有关详细信息,请参阅docs

$scope.$watch('activeFilterAttributes', function() {
  // ...
}, true); // <-- objectEquality

添加该参数,一切顺利。

答案 1 :(得分:5)

现在接受的答案有点过时了,与AngularJS 1.1.4一样,$WatchCollection函数被添加用于数组和其他集合,这比带有深度的$Watch要便宜得多-equality标志设置为true。

所以这个新功能现在在大多数情况下都是可取的。

有关$watch函数

之间更详细的差异,请参阅this article