Using ControllerAs with a Directive

Ryan Langton picture Ryan Langton · Aug 6, 2015 · Viewed 34.4k times · Source

I'm trying to follow John Papa's angularJS style guide here and have started switching my directives to using controllerAs. However, this is not working. My template cannot seem to access anything assigned to vm. See this very simple plnkr example that exhibits the behavior.

http://plnkr.co/edit/bVl1TcxlZLZ7oPCbk8sk?p=preview

angular
    .module('app', []);

angular
    .module('app')
    .directive('test', test);

function test() {
    return {
        restrict: 'E',
        template: '<button ng-click="click">{{text}}</button>',
        controller: testCtrl,
        controllerAs: 'vm'
    }
}

angular
    .module('app')
    .controller('testCtrl', testCtrl);

function testCtrl() {
  var vm = this;
  vm.text = "TEST";
}

Answer

Tr1stan picture Tr1stan · Aug 6, 2015

When using the controllerAs syntax you don't access the $scope as you would normally, the variable vm is added to the scope, so your button needs to become:

<button ng-click="click">{{vm.text}}</button>

Notice the vm. added to the beginning of text.

Here is a fork of your Plunk with the fix applied


Q: Do you know how I would access attributes passed through as attributes to the directive, example "scope: { text: '@' }"? Am I then forced to use $scope on the controller and set vm.text = $scope.text?

A: In the article you reference, there is a section y075 that talks about just this scenario. Look into bindToController:

return {
    restrict: 'E',
    template: '<button ng-click="click">{{text}}</button>',
    controller: testCtrl,
    controllerAs: 'vm',
    scope: {
        text: '@'
    },
    bindToController: true // because the scope is isolated
};

Then you should be able to access vm.text