I have a table and the user can chose to filter rows in the table based on certain columns and certain values for these columns. The object structure to keep track of this filter looks like:
$scope.activeFilterAttributes = [
{
"columnName": "city",
"values": ["LA", "OT", "NY"]
},
{
"columnName": "weather",
"values": ["humid", "sunny"]
}
];
So the objects in the array contain the "columnName" and "values" key. "columnName" signifies the column to consider for the filter while "values" contains the filter values. Basically, the above array will result in rows in the table for which the city column contains "LA", "OT" or "NY" as values and the weather column contains "humid" or "sunny" as the values. Other rows which do not contain these values are not shown.
To help understand this object better, if the user wishes to see only those rows who have "LA" or "NY" in the column for "city", the resultant array will look like:
$scope.activeFilterAttributes = [
{
"columnName": "city",
"values": ["LA", "NY"]
},
{
"columnName": "weather",
"values": []
}
];
The user sets or removes these filters. Whenever this happens, the above array is updated. This update happens correctly and I have verified it - no problem here.
The problem lies with the $watch(). I have the following code:
$scope.$watch('activeFilterAttributes', function() {
//Code that should update the rows displayed in the table based on the filter
}}
While $scope.activeFilterAttributes
is updated properly as and when the user updated the filter in the UI, the $watch is not triggered when this is updated. It is triggered the first time when the application loads but future updates have no effect on this.
I have created a fiddle to demonstrate this: http://jsfiddle.net/nCHQV/
In the fiddle, $scope.info
represents the rows of the table, so to speak;$scope.data
represents the filter.
Clicking on the button is equivalent to updating the filter(in the case of the fiddle - the data) and thus updating the rows displayed in the table(in the case of the fiddle - the info). But as can be seen, the info is not updated on clicking the button.
Shouldn't $scope.$watch
be triggered when the array of objects changes?
The $watch
method takes an optional third parameter called objectEquality
that checks that the two objects are equal, rather than just share the same reference. This is not the default behavior because it is a more expensive operation than the reference check. Your watch isn't being triggered because it still refers to the same object.
See the docs for more info.
$scope.$watch('activeFilterAttributes', function() {
// ...
}, true); // <-- objectEquality
Add that parameter and all is well.
Accepted answer is a bit out of date now as with AngularJS 1.1.4 the $WatchCollection
function was added for use with arrays and other collections, which is far less expensive than a $Watch
with the deep-equality flag set to true.
So this new function is now preferable in most situations.
See this article for more detailed differences between $watch
functions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With