Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Same "controller as" name in angular js directive breaks function in parent controller

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:

enter image description here

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?

like image 924
Staeff Avatar asked Feb 09 '23 20:02

Staeff


1 Answers

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.

like image 99
Loïc Faure-Lacroix Avatar answered Feb 12 '23 11:02

Loïc Faure-Lacroix