Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting modules in extended controller(ES6) causes Unknown provider error

I have a controller class ModalCtrl and I want to create a child class ModalCtrlChild extends ModalCtrl. Problem is when I try to do that i get an unknown provider error in any of the modules injected in ModalCtrl.

I used this generator to build the project and it uses NgInject behind the scenes to inject the dependencies, I suspect there's something funny happening there.

ModalCtrl:

export default class ModalCtrl {
  static get UID(){
    return "ModalCtrl"
  }
  ... // all my ModalCtrl methods here

 /* @ngInject */
  constructor(ngDialog, PreoModalType, OutletService, $q, $timeout, VenueService) {
    "ngInject";
    ... // ModalCtrl constructor logic initing variables
  }
}

ModalCtrlChild:

import ModalCtrl from '../../preoModal.controller';

export default class ModalCtrlChild  extends ModalCtrl{
  static get UID(){
    return "modalCtrlChild"
  }

  /* @ngInject */
  constructor() {
    // "ngInject";
    console.log("in super constructor");
    super();
  }
}

Error:

Error: [$injector:modulerr] Failed to instantiate module function ModalCtrlChild() due to:
Error: [$injector:unpr] Unknown provider: ngDialog
http://errors.angularjs.org/1.5.3/$injector/unpr?p0=ngDialog

And ngDialog is DEFINITELY imported and working. If delete extends ModalCtrl from ModalCtrlChild I don't get any errors and my code runs fine but I'm not able to get the inheritance I need. Any ideas appreciated.

EDIT

I had tried eenagy's answer before posting the question, that doesn't work either, as the problem seems to be in the child class injects, not in the parent's class injects.

sourdoughdetzel, tried your suggestion:

  1. Removed annotation and dependencies from ModalCtrlChild
  2. Removed annotation and dependencies from ModalCtrl but left them in child

Got the exact same error:

Error: [$injector:modulerr] Failed to instantiate module function PreoModalController_Form() due to:
Error: [$injector:unpr] Unknown provider: ngDialog

I suspect this has to do with the way babel is constructing the extended class and is not allowing ngInject to do it's work. I'm trying to work out a way of doing manual injections here, which should solve the problem and prove that this is the issue as I do not know enough about how babel's work to fix this.

like image 877
caiocpricci2 Avatar asked May 04 '16 15:05

caiocpricci2


2 Answers

My guess is that ngInject is not doing what it is supposed to be doing behind the scenes when you call "super()" from a subclass' constructor. I wasn't seeing much on ngInject when searching around, but it may be getting short-circuited because of the manual call to the constructor that is happening.

If you take the dependencies into the ModalCtrlChild controller and uncomment the "ngInject" string, then pass them along to the super() call, does it work as expected?

like image 109
sourdoughdetzel Avatar answered Nov 03 '22 22:11

sourdoughdetzel


The error message actually tells you what missing.

Unknown provider: ngDialog

You need to declare your dependencies in your subclass too.

So instead of this

import ModalCtrl from '../../preoModal.controller';

export default class ModalCtrlChild  extends ModalCtrl{
  static get UID(){
    return "modalCtrlChild"
  }

  /* @ngInject */
  constructor() {
    // "ngInject";
    console.log("in super constructor");
    super();
  }
}

You need to pass the parameters in.

import ModalCtrl from '../../preoModal.controller';

export default class ModalCtrlChild  extends ModalCtrl{
  static get UID(){
    return "modalCtrlChild"
  }

  /* @ngInject */
  constructor(ngDialog, PreoModalType, OutletService, $q, $timeout, VenueService) {
    // "ngInject";
    console.log("in super constructor");
    super(ngDialog, PreoModalType, OutletService, $q, $timeout, VenueService);
  }
}

There is no way that ngInject would know what dependencies are needed. How should it know? In the real world there could be dozens of subclasses of ngDialog which matches the contract and passable as a parameter. You need to specify which one is needed so it can pass it in.

As a example imagine if you have a subclass of ngDialog called ngPopupDialog.

And your example subclass. The following could be used instead of ngDialog, and would match the super.

import ModalCtrl from '../../preoModal.controller';

export default class ModalCtrlChild  extends ModalCtrl{
  static get UID(){
    return "modalCtrlChild"
  }

  /* @ngInject */
  constructor(ngPopupDialog, PreoModalType, OutletService, $q, $timeout, VenueService) {
    // "ngInject";
    console.log("in super constructor");
    super(ngPopupDialog, PreoModalType, OutletService, $q, $timeout, VenueService);
  }
}
like image 23
eenagy Avatar answered Nov 03 '22 20:11

eenagy