Partha Sarathi Ghosh
Partha Sarathi Ghosh

Reputation: 11576

Unknown provider: $controller

I can access $controllerProvider but can not access $controller in the following method

angular.module(MODULE_NAME, ['common'])
    .config(['$routeProvider','$controllerProvider',
      function($routeProvider, $controllerProvider) {
        console.log($controllerProvider);//defined
        console.log($controller);//undefined
}]);

If I use $controller as dependency injection, it is giving

Unknown provider: $controller

But I need to access it, How do I do that

EDIT

I need this because I want to check my controller exists not not. Here is the post where from I am using this code

try {
     $controller(controllerName);
     listControlerName = MODULE_NAME+'ListController';
} catch (error) {
     listControlerName = 'CommonListController';
}

CONTEXT

I am creating architecture of a project. My project structure as follows.

  1. I have one COMMON module. with ListController, EditController, ViewController
  2. I have some other modules like MOD1, MOD2 etc with MOD1ListController, MOD1EditController, MOD1ViewController so on.
  3. Those module specific controller extend corresponding controller from Common Module.

Now my plan is while a new module (MODX) need to be developed, then if there is some extra functionality, then only developer will create a new MODXListController for that module by inheriting common ListController. Otherwise they need not to create any thing.

So system will check if that module contains MODXListController or not. If not then system will use Common ListController.

I do not want to create a MODXListController which inherits common ListController but does not do any extra change. Because I have lots of module nearly 25 and all of then are sharing same functionality mostly.

Upvotes: 3

Views: 1038

Answers (3)

Estus Flask
Estus Flask

Reputation: 222474

Without explicitly inheriting all controllers (which is acceptable but verbose solution), a good alternative is to wrap controller switching functionality into mod-controller directive (similar to ng-controller), something like that:

angular.module('common', [])
.constant('MODULE_NAME', 'Common')
.constant('modControllers', [])
.controller('CommonEditController', ...);
.controller('CommonListController', ...);
.directive('modController', function (MODULE_NAME, modControllers) {
  return {
    restrict: 'A',
    scope: true,
    priority: 500,
    controller: function ($controller, $attrs, $scope) {
      var ctrlName = (modControllers.indexOf($attrs.modController) >=0 ? MODULE_NAME : 'Common') + $attrs.modController;

      angular.extend(this, $controller(ctrlName, { $scope: $scope }));
    });
  };
});

angular.module('mod1', ['common'])
.constant('MODULE_NAME', 'Mod1')
.constant('modControllers', ['ListController']);
.controller('Mod1ListController', function ($controller) {
  angular.extend(this, $controller('CommonListController');
  ...
});

When the controller should be specified in application code rather than view (i.e. route and directive controllers), the similar thing can be done with controller factory.

angular.module('common')
.provider('ctrlFactory', function (MODULE_NAME, modControllers) {
  function factoryFn(ctrlName) {
    return (modControllers.indexOf(ctrlName) >=0 ? MODULE_NAME : 'Common') + ctrlName;
  };

  this.get = this.$get = factoryFn;
});

It can be injected into directives and used as

...
controller: ctrlFactory('ListController')

Due to the fact that it returns controller name instead of $controller instance and depends only on constant services (MODULE_NAME, modControllers), service provider can also be used in the same way as service instance to declare route controllers in config block:

...
controller: ctrlFactoryProvider.get('ListController')

Because $controller doesn't expose the list of registered controllers, try-catching it comes to mind as automatic solution, and it is the last thing the one may want to do: besides it is a hack, it just suppresses possible exceptions and damages testability.

Upvotes: 1

Vivek
Vivek

Reputation: 13238

You can not inject $controller into config

Although you can use the following service to check if your controller is defined.

angular.service('ControllerChecker', ['$controller', function($controller) {
  return {
    exists: function(controllerName) {
      if(typeof window[controllerName] == 'function') {
        return true;
      }
      try {
        $controller(controllerName);
        return true;
      } catch (error) {
        return !(error instanceof TypeError);
      }
    }
  };
}]);

Now you can inject ControllerChecker and call its exists(CtrlName) function to check whether your controller is defined or not.

Upvotes: 0

J-D
J-D

Reputation: 1575

In .config you can only use providers (e.g. $routeProvider).

In .run you can only use instances of services (e.g. $route).

$controller is of type service which can not be used in .config.

For more detail on this read here.

The detailed discussion on Stack Overflow at this thread shows what can be injected into others.

Upvotes: 0

Related Questions