Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

controller not injected to link function when require used #11903

Closed
vlio20 opened this issue May 19, 2015 · 6 comments
Closed

controller not injected to link function when require used #11903

vlio20 opened this issue May 19, 2015 · 6 comments

Comments

@vlio20
Copy link

vlio20 commented May 19, 2015

I have this tag:

<input name="username" type="text" ng-model="vm.username" available>

and this 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);
  }

Now if I remove require: ngModel the controller is injected to the linking function:

  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;
  }

...

Is it a bug?

@vlio20
Copy link
Author

vlio20 commented May 19, 2015

The work around:

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

    function linker(scope, elem, attrs, ngModel) {
      var ctrl = scope.ctrl; //add this 
      ctrl.model = ngModel; 
    }

    return directive;
  }

@gkalpak
Copy link
Member

gkalpak commented May 19, 2015

This is how things work (for some reason 😄).

Namely, 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];
    ...
  }
})

@gkalpak
Copy link
Member

gkalpak commented May 19, 2015

From a quick look, the 1st situation (passing the directive's controller if there is no require) doesn't seem to be documented. Should we document it ?

@Narretz
Copy link
Contributor

Narretz commented May 19, 2015

Yeah, we should document this. It's a bit confusing, if you not always require all controllers. But I'm pretty sure it says nowhere that the controllers get passed as extra fn arguments.

@Narretz Narretz added this to the Backlog milestone May 19, 2015
@gkalpak
Copy link
Member

gkalpak commented May 19, 2015

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).

@Narretz
Copy link
Contributor

Narretz commented May 19, 2015

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.

@Narretz Narretz self-assigned this Jun 6, 2015
Narretz added a commit to Narretz/angular.js that referenced this issue Jun 8, 2015
@Narretz Narretz closed this as completed in c210ff5 Jun 8, 2015
netman92 pushed a commit to netman92/angular.js that referenced this issue Aug 8, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants