TL;DR: updating a property on a watched object does not seem to fire the watch when the property is a function .
Live example
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.
Dead example
View
<main-dir config="configObject"></main-dir>
Directive
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);
}
};
});
Controller
//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!