Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing parent scope in directive when using controllerAs

I currently have a directive that's using properties from the parent controller's scope:

.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'm moving over to controllerAs syntax in my controllers, but I don't know how to get a reference to the controller object in my directive's 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 issue.

I also found this article that's trying to explain something similar, but in this case he's just reusing the exact same controller.

like image 455
diplosaurus Avatar asked Sep 14 '15 19:09

diplosaurus


1 Answers

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

In the controller, you could access either this.name or $scope.vm.name, they would be functionally equivalent. However, in other controllers, this would refer to that specific controller, and thus this.name would not work.

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

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

I do recommend using an isolate scope if possible, however, since it will allow you to completely eliminate the need to inject $scope into your directives, and allow your directive to be self contained, and reusable.

Side note, bindToController: true, does nothing if you are not using an isolate scope; when you are using an isolate scope, it creates properties on the isolated controller to match the scope passed in, allowing for you to access the passed in values without needing $scope.

like image 182
Claies Avatar answered Sep 28 '22 05:09

Claies