How do I access a controller require'd from another controller?

I have an Angular 1.3 module that looks something like this (directive that requires a parent directive using controllerAs

):

angular.module('fooModule', [])

.controller('FooController', function ($scope) {
  this.doSomething = function () {
    // Accessing parentDirectiveCtrl via $scope
    $scope.parentDirectiveCtrl();
  };
})

.directive('fooDirective', function () {
  return {
    // Passing in parentDirectiveCtrl into $scope here
    link: function link(scope, element, attrs, parentDirectiveCtrl) {
      scope.parentDirectiveCtrl = parentDirectiveCtrl;
    },
    controller: 'FooController',
    controllerAs: 'controller',
    bindToController: true,
    require: '^parentDirective'
  };
});

      

Here I am just using $scope

to go through parentDirectiveCtrl

, which seems a little awkward.

Is there any other way to access the require

-ed controller from a directive controller without a bind function?

+3


source to share


3 answers


You should use a function link

to get the require

-ed controllers , but you don't need to use scope to pass the controller reference to its place. Instead, pass it directly to your controller:

.directive('fooDirective', function () {
  return {

    require: ["fooDirective", "^parentDirective"],

    link: function link(scope, element, attrs, ctrls) {
      var me     = ctrls[0],
          parent = ctrls[1];

      me.parent = parent;
    },
    controller: function(){...},
  };
});

      



Be careful, because the controller is working to link, so the controller in this.parent

there undefined

until the communication function is started. If you need to know exactly when this will happen, you can always use a controller function to pass the controller parentDirective

:

link: function link(scope, element, attrs, ctrls) {
  //...

  me.registerParent(parent);
},
controller: function(){
  this.registerParent = function(parent){
    //...
  }
}

      

+3


source


There is a way to avoid being used $scope

to access the parent controller, but you must use a function link

. Angular documentation says :

Require

Require another directive and inject its controller as the fourth argument to the bind function ...

Option 1

Since it controllerAs

creates a namespace in scope

your controller, you can access that namespace inside your function link

and place the required controller directly on the controller childDirective

instead of using it $scope

. Then the code will look like this.

angular.module('app', []).
  controller('parentController', function() {
    this.doSomething = function() {
      alert('parent');
    };
  }).
  controller('childController', function() {
    this.click = function() {
      this.parentDirectiveCtrl.doSomething();
    }
  }).
  directive('parentDirective', function() {
    return {
      controller: 'parentController'
    }
  }).
  directive('childDirective', function() {
    return {
      template: '<button ng-click="controller.click()">Click me</button>',
      link: function link(scope, element, attrs, parentDirectiveCtrl) {
        scope.controller.parentDirectiveCtrl = parentDirectiveCtrl;
      },
      controller: 'childController',
      controllerAs: 'controller',
      bindToController: true,
      require: '^parentDirective'
    }
  });

      

Plunker



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

Option 2

I usually don't use controllers at all in my directives and can't use functions through services. If you don't need to mess with the isolated scopes of parent and child directives, just add the same service to both of them and enable all functionality.

angular.module('app', []).
  service('srv', function() {
    this.value = '';
    this.doSomething = function(source) {
      this.value = source;
    }
  }).
  directive('parentDirective', ['srv', function(srv) {
    return {
      template: '<div>' + 
                  '<span ng-click="srv.doSomething(\'parent\')">Parent {{srv.value}}</span>' +
                  '<span ng-transclude></span>' +
                '</div>',
      transclude: true,
      link: function(scope) { scope.srv = srv; }
    };
  }]).
  directive('childDirective', ['srv', function(srv) {
    return {
      template: '<button ng-click="srv.doSomething(\'child\')">Click me</button>',
      link: function link(scope) { scope.srv = srv; }
    }
  }]);

      

Plunker



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

+1


source


Good question! Angular allows you to pass in a "parent" controller. You already have a parameter in your link function. This is the fourth parameter. I named it ctrl for simplicity. You don't need the line scope.parentDirectiveCtrl = parentDirectiveCtrl that you have.

.directive('fooDirective', function () {
  return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, ctrl) {
  // What you had here is not required.
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'};});

      

Now your parent controller has

this.doSomething=function(). 

      

You can access this doSomething as

ctrl.doSomething().

      

0


source







All Articles