Reputation: 2324
TL;DR: updating a property on a watched object does not seem to fire the watch when the property is a function .
See this Plnkr exampl.
The config
object's properties can be changed by clicking the buttons in the example. The objects are in sync (between directive and controller), and the $watch
function in the directive (which simply ups a counter in this case) is called when a property is changed. Except when a function property is changed, which is what I do not understand.
<main-dir config="configObject"></main-dir>
myApp.directive('mainDir', function () {
return {
restrict: 'E',
scope: {config: '='},
link: function (scope, el) {
//(initialisation code)
scope.$watch("config", function (config) {
if (!config) return;
// do stuff with config object
}, true);
}
};
});
//init:
$scope.configObject = {
propA: "value",
propB: [1,2,3],
propC: {key0: 3, key1: "value"},
propD: function(x) {return x+1;}
}
//elsewhere:
$scope.configObject.propA = "other value"; //fires watch in directive
//or
$scope.configObject.propB = [3,2,1]; //fires watch in directive
//or
$scope.configObject.propB.push(5); //fires watch in directive
//or
$scope.configObject.propC = {key0: 1, key2: 34}; //fires watch in directive
//or
$scope.configObject.propC["key100"] = "newValue"; //fires watch in directive
//
// ... BUT ...
//
$scope.configObject.propD = function (x) {return x+2;} //does NOT fire watch in directive
So, in short: I can get the $watch
to fire on changes to the object's properties. But that doesn't seem to work if the property is a function.
Workaround:
When changing a property that is a function, I add a line changing a non-function property to fire the watch, like so:
$scope.configObject.propD = function (x) {/*...new function def...*/};
$scope.configObject.xxx = Math.random(); //<-- causes watch to fire
Does anyone know why that is the case? Can I get the $watch
to fire also on changes to function properties of the config object?
Thanks!
Upvotes: 0
Views: 1193
Reputation: 61
scope.$watch("config.propD") will watch reference to function instead of returning value scope.$watch("config.xxx") will watch return value from Math.random because you called function
Simplest way is to use $watchCollection documentation but it's not perfect one
scope.$watchCollection('config',
function(config) {
scope.caught++;
}
);
Another way is to program collection of $watch'ers it's work slightly better:
angular.forEach(scope.config, function(value, key) {
scope.$watch(function() {
return scope.config[key];
}, function(config) {
scope.caught2++;
}, true);
});
Upvotes: 1