I have an issue where a directive with an isolate scope is not making changes via binding to its parent.parent scope.
In summary, I would expect that changes made to a property in the directive's isolate scope which is bound to a parent property would propagate all the way up parent scopes for that property (the property was inherited from a parent.parent scope to begin with), but it doesn't. It only changes the value on the immediate parent scope, while the parent.parent scope has the old value. Worse, any changes to the parent.parent scope property no longer trickle down to the isolate scope or its immediate parent. I understand this is the normal behavior of Javascript's prototype inheritance which Angular scopes are built on, but it's not wanted in this case of two-way data binding and I'm looking for a solution in Angular.
Here is an example of the behavior: http://jsfiddle.net/abeall/RmDuw/344/
My HTML contains a controller div (MyController1
), in it is another controller div (MyController2
), and in that is a directive (MyDirective
):
<div ng-controller="MyController">
<p>MyController1: {{myMessage}} <button ng-click="change()">change</button></p>
<div ng-controller="MyController2">
<p>MyController2: {{myMessage}} <button ng-click="change()">change</button></p>
<p>MyDirective: <my-directive message="myMessage"/></p>
</div>
</div>
The Javascript defines myMessage
on the outer MyController
scope, the inner MyController2
scope inherits and binds myMessage
to message
on the directive, and the MyDirective
defines message
as an isolate scope property. At each level a change()
function is defined which changes the local message property:
var app = angular.module('myApp', []);
function MyController($scope) {
var count = 0;
$scope.myMessage = "from controller";
$scope.change = function(){
$scope.myMessage = "from controller one " + (++count);
}
}
function MyController2($scope) {
var count = 0;
$scope.change = function(){
$scope.myMessage = "from controller two " + (++count);
}
}
app.directive('myDirective', function() {
return {
restrict: 'E',
replace: true,
template: '<span>Hello {{message}} <button ng-click="change()">change</button></span>',
scope: {
message: "="
},
link: function(scope, elm, attrs) {
var count = 0;
scope.change = function(){
scope.message = "from directive " + (++count);
}
}
};
});
What you'll notice is that:
If you click the MyController1
's change button a few times, all levels are updated (it inherits downwards).
If you then click the MyDirective
's change button, it updates MyController2
(binding upward) but does not change MyController1
in any way.
After this point, clicking MyController1
's change button no longer trickles down to MyController2
and MyDirective
scope, and vice versa. The two are now separated from each other. This is the problem.
So my question is:
Does Angular have a way to allow binding or inheritance of scope properties (myMessage
in this case) to trickle all the way up parent scopes?
If not, in what way should I sync changes in a directive's isolate scope to a parent.parent controller scope's properties? The directive can not know about the structure of its parents.
as @Claies mentioned, using controller as
is a great idea. This way you can be direct about which scope you want to update, as well as easily being able to pass scopes around in methods.
Here is a fiddle of the results you were likely expecting
Syntax: ng-controller="MyController as ctrl1"
Then inside: {{ctrl1.myMessage}}
or ng-click="ctrl1.change()"
and click="ctrl2.change(ctrl1)"
This changes the way you write your controller by leaving out the $scope
dependency unless you need it for other reasons then holding your model.
function MyController () {
var count = 0
this.myMessage = "from controller"
this.change = function () {
this.myMessage = "from controller one " + (++count)
}
}
function MyController2 () {
var count = 0
this.change = function (ctrl) {
ctrl.myMessage = "from controller two " + (++count)
}
}