sevenLee
11/3/2015 - 5:48 PM

Controller not injected to link function when require used. From: https://github.com/angular/angular.js/issues/11903

Controller not injected to link function when require used. From: https://github.com/angular/angular.js/issues/11903

angular.module('friendlyBetsApp')
    .directive('available', RegistrationCtrl);

  function RegistrationCtrl() {
    var directive = {
      restrict: 'A',
      //require: 'ngModel',
      link: linker,
      scope:true,
      controller: ExampleController,
      controllerAs: 'ctrl',
      bindToController: true
    };

    function linker(scope, elem, attrs,/* ngModel,*/ ctrl) {
      ctrl.model = ngModel; //ctrl is defined, and ngModel is undefined (daaa) 
      ctrl.setAsLoading(true);

    }

    return directive;
  }

...
angular.module('friendlyBetsApp')
    .directive('available', RegistrationCtrl);

  function RegistrationCtrl() {
    var directive = {
      restrict: 'A',
      require: 'ngModel',
      link: linker,
      scope:true,
      controller: ExampleController,
      controllerAs: 'ctrl',
      bindToController: true
    };

    function linker(scope, elem, attrs, ngModel, ctrl) {
      ctrl.model = ngModel; //ctrl is undefined
      ctrl.setAsLoading(true);

    }

    return directive;
  }

  function ExampleController($scope) {

  }

  ExampleController.prototype.setAsLoading = function (bool) {
    this.model.$setValidity('loading', bool);
  }

But I'm pretty sure it says nowhere that the controllers get passed as extra fn arguments.

That's the problem :) It says: no controller(s) required: undefined (which is not true).

You are right. I was thinking about this function linker(scope, elem, attrs, ngModel, ctrl) {

because this will never work. ctrl is the transclude fn, if provided. If more than one ctrl is required, ngModel would be an array of them.

if the directive has a controller and doesn't specify a require property, then the 4th argument passed to the linking functions is the directive's controller.

If the directive specifies a require property (either String or Array), then the 4th argument passed to the linking functions is the required controller(s) (not the directive's controller).

The solution is to also require the directive itself:

.directive('foo', function fooDirective() {
  return {
    ...
    require: ['foo', 'ngModel'],
    controller: FooCtrl,
    link: fooPostLink,
  };

  function FooCtrl() {}

  function fooPostLink(scope, elem, attrs, ctrls) {
    var fooCtrl = ctrls[0];
    var ngModelCtrl = ctrls[1];
    ...
  }
})