I was playing around with the bindToController
option for directives. I stumbled upon a seemingly strange difference between the behaviour using a child scope compared to an isolated scope. When I use an isolated scope, an new scope is created for the directive, but changes to the bound controller attributes are forwarded to the parent scope. Yet when I use a child scope instead, my example breaks. (Using bindToController
using child scopes should be allowed according to http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html#improvements-in-14 )
The code:
{
restrict: 'E',
scope: {},
controller: 'FooDirCtrl',
controllerAs: 'vm',
bindToController: {
name: '='
},
template: '<div><input ng-model="vm.name"></div>'
};
Working demo https://jsfiddle.net/tthtznn2/
The version using a child scope:
{
restrict: 'E',
scope: true,
controller: 'FooDirCtrl',
controllerAs: 'vm',
bindToController: {
name: '='
},
template: '<div><input ng-model="vm.name"></div>'
};
Demo: http://jsfiddle.net/ydLd1e00/
The changes to name are forwarded to the child scope, but not to the parent scope. This in contrast to binding to an isolated scope. Why is this?
This is because you are using the same alias for both controllers (and has nothing to do with object vs string value as mentioned in the comments).
As you might know, the controller as alias
syntax is merely creating an alias
property on scope and sets it to the controller instance. Since you are using vm
as the alias in both cases (MainCtrl
and FooDirCtrl
) you are "shadowing" the MainCtrl
alias in the case of the normal child scope.
(In this context, "normal" means "prototypally inheriting from parent scope".)
Thus, when you are trying to evaluate vm.name
(vm
for MainCtrl
) on the new scope to get the "parent value", it is actually evaluating FooDirCtrl.name
(which is undefined) and the same happens when you are trying to assign back to the parent scope.
The isolate scope version is not affected, since the scope is not inheriting from it's parent scope.
Updated fiddle
UPDATE:
Taking a closer look at the source code, this might be a bug (because support for bindToController
on non-isolate scopes was added "retroactively").
We seem to have been getting away with this bug, because of the prototypal inheritance, but when the names collide we are out of luck.
I have to take a closer look to make sure if it's indeed a bug and if it's "fixable", but for now you can work around it by using different aliases for your controllers (see fiddle above).
That's (part of) why I don't like using vm
as my conroller alias (despite it being suggested by popular style-guides) :)
Let's track this in angular.js#13021.
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