Access to parent scope in directive when using controllerAs

I currently have a directive that uses properties from the scope of the parent controller:

.controller('MainCtrl', function($scope) { $scope.name = 'My Name'; }) .directive('myDirective', function() { return { scope: true, controller: function($scope) { console.log($scope.name); // logs 'My Name' } }; }) 

Now I move on to the controllerAs syntax in my controllers, but I donโ€™t know how to get the reference to the controller object in my controller.

 .controller('MainCtrl', function() { var vm = this; vm.name = 'My Name'; }) .directive('myDirective', function() { return { scope: true, controller: function($scope) { console.log(vm.name); // logs 'Undefined' } }; }) 

Here's a plunkr illustrating the problem.

I also found this article that is trying to explain something like this, but in this case it just reuses the same controller.

+5
source share
2 answers

When you use the ControllerAs syntax, a property is created on the $scope object, which is an alias of your controller. for example, ng-controller="MainCtrl as vm" gives you $scope.vm . $scope implied in HTML, so accessing vm.name in HTML is the same as accessing $scope.vm.name in JavaScript.

In the controller, you can access this.name or $scope.vm.name , they will be functionally equivalent. However, in other controllers, this will refer to this particular controller, and thus this.name will not work.

Therefore, in this case, you can access the required property in the directive controller using $scope.vm.name . http://plnkr.co/edit/WTJy7LlB7VRJzwTGdFYs?p=preview

However, you probably also want to use the ControllerAs syntax with this directive; in this case, I recommend using a unique name instead of using vm for your controller names, which can help determine which controller you are accessing. MainCtrl as main , and then referring to main.name will be much clearer.

I recommend using a scope if possible, however, as this will completely eliminate the need to embed $scope in your directives and allow your directive to be self-contained and reused.

A side note, bindToController: true, does nothing unless you use the selection area; when you use the isolation area, it creates the properties of the isolated controller to match the passed area, allowing you to access the passed values โ€‹โ€‹without the need for $scope .

+9
source

One option is to go through the $scope chain until you find vm.

 app.directive('myDir', function() { return { restrict: 'E', scope: true, template: '<div>my directive</div>', bindToController: true, controller: function($scope) { console.log($scope.name2); // logs 'bound to the controller scope' console.log($scope.$parent.vm.name); // logs 'bound to the controller vm' } }; }); 

However, it can be really fragile and it smells a bit.

A more sophisticated and thoughtful approach is to bind the properties of your control area to your directive via the passed argument.

HTML:

 <my-dir name="vm.name" /> 

JS:

 app.directive('myDir', function() { return { restrict: 'E', scope: { name: "=" }, template: '<div>my directive</div>', bindToController: true, controller: function($scope) { console.log($scope.name); // logs 'bound to the controller vm' } }; }); 

See plunkr

+2
source

All Articles