Update:
Thanks to the reference to this blog post, I need to update my answer. Since AngularJS 1.4 it really seems, that you can use
scope: {},
bindToController: {
variable: '='
}
which will do the (exact) same thing as the old syntax:
scope: {
variable: '='
},
bindToController: true
The useful lines from the AngularJS source code to explain this behavior:
if (isObject(directive.scope)) {
if (directive.bindToController === true) {
bindings.bindToController = parseIsolateBindings(directive.scope,
directiveName, true);
bindings.isolateScope = {};
} else {
bindings.isolateScope = parseIsolateBindings(directive.scope,
directiveName, false);
}
}
if (isObject(directive.bindToController)) {
bindings.bindToController =
parseIsolateBindings(directive.bindToController, directiveName, true);
}
Source: AngularJS 1.4.0
Original answer:
Hopefully, I can explain you why this behavior you experienced is correct and where you did missunderstand the concept of scope binding there.
Let me explain, what you did in your first code snippet:
.directive('mdAddress', function mdAddress() {
var directive = {
restrict: 'EA',
scope: {},
bindToController: {
address: '='
},
templateUrl: 'modules/address/address.html',
controller: AddressController,
controllerAs: 'dir'
};
With scope: {}
, you created an isolated scope (without any inheritance) for your mdAddress
directive. That means: No data is passed between the parent controller and your directive.
Having this in mind, regarding your second code snippet:
<md-address address="vm.address"></md-address>
vm.address
from your parent controller/view will be assigned as expression to the address attribute of the directive, but as you defined an isolated scope before, the data is not passed into AddressController
and therefore not available in the bindToController
value.
Let's think of the scope
object definition as the "which data will be passed in" and the bindToController
as the "which data will be available in my view's controllerAs object".
So, now let's have a look at the last (and working code snippet):
.directive('mdAddress', function mdAddress() {
var directive = {
restrict: 'EA',
scope: {
address: '='
},
bindToController: true,
templateUrl: 'modules/address/address.html',
controller: AddressController,
controllerAs: 'dir'
};
There you created an isolated scope, too, but this time you added the address
attribute to be passed in as an expression. So now the address
you passed in from the view in the second snippet will be available in the controller's scope. Setting bindToController: true
now, will bind all the current scope's properties to the controller (or more likely the controllerAs object). And now, it works as you would expect, because data will be passed in to the scope and data will be passed out to the controller's template scope.
Did that brief overview help you to better understand the concept of the scope
and bindToController
definition objects?