I've a controller with some items for ng-repeat
and each item should get a random color so I use ng-style
with a function in that controller called randColor(...)
.
app.controller('TestController', function() {
var vm = this;
vm.items = [ { name: 'item 1' } , { name: 'item 2'} ];
vm.randColor = function (item) {
if (!item) {
return 'red';
}
else if (!item.color)
{
var color = 'rgb('
+ _.random(0, 255) + ','
+ _.random(0, 255) + ','
+ _.random(0, 255) + ')';
item.color = color;
}
return item.color;
};
});
I'm using the "controller as" syntax for this and I usually always use vm
as the short name of my controllers. I've never had a problem with doing so, even when naming "sub"-controllers the same way.
But now I've tried to do the same thing with a directive and suddenly my randColor(...)
function stopped working.
Here is a plunker of my problem.
HTML:
<body ng-controller="TestController as vm">
<!-- This works -->
<h3>Without Directive (controllerAs: 'vm')</h3>
<div ng-repeat="item in vm.items">
<div ng-style="{ background: vm.randColor(item) }" class="container">
<h4>{{ item.name }}</h4>
<div ng-controller="TestDirectiveController as vm">
<div>{{ vm.title }}</div>
</div>
</div>
</div>
<!-- This works -->
<h3>Test Directive Alternative (controllerAs: 'directiveVM')</h3>
<div ng-repeat="item in vm.items">
<div ng-style="{ background: vm.randColor(item) }" class="container">
<h4>{{ item.name }}</h4>
<test-directive-alt></test-directive-alt>
</div>
</div>
<!-- This DOES NOT work -->
<h3>Test Directive (controllerAs: 'vm')</h3>
<div ng-repeat="item in vm.items">
<div ng-style="{ background: vm.randColor(item) }" class="container">
<h4>{{ item.name }}</h4>
<test-directive></test-directive>
</div>
</div>
</body>
JS:
app.controller('TestDirectiveController', function() {
var vm = this;
vm.title = 'test';
});
app.directive('testDirective', function() {
return {
restrict: 'EA',
controller: 'TestDirectiveController',
controllerAs: 'vm',
bindToController: true,
template: '<div>{{ vm.title }}</div>'
};
});
app.directive('testDirectiveAlt', function() {
return {
restrict: 'EA',
controller: 'TestDirectiveController',
controllerAs: 'directiveVM',
bindToController: true,
template: '<div>{{ directiveVM.title }}</div>'
};
});
Output:
I know I could just use a different name for the controller as in my example, but why does this happen in the first place?
And is there a way to get it working with the same name?
The problem you're facing seems to be related to the fact that the directive is being executed on the same scope as the scope where the controller is defined as vm
.
What you need to do is to create a new scope scope: {}
within the directive.
app.directive('testDirective', function() {
return {
restrict: 'EA',
scope: {},
controller: 'TestDirectiveController',
controllerAs: 'vm',
bindToController: true,
template: '<div>{{ vm.title }}</div>'
};
});
With that, the controllerAs
should create a new vm
attribute in the directive scope.
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