Search code examples
javascriptangularjstypescriptangularjs-factory

Inject factory into a controller angularjs + typescript


I've been trying to inject factory into a controller using both Angularjs and Typescript, but I'm getting this error Error: [$injector:unpr] http://errors.angularjs.org/1.2.9/$injector/unpr?p0=AuthenticationProvider%20%3C-%20Authentication.

I've been researching around, but can't find a solution because what I did is similar to some of the solution.

Here is my Login controller module

import Authentication = require('AuthenticationService');
module LoginController{

export interface UIMainScope extends ng.IScope {
    login: (credential: any) => void;
}

export class Controller {
    static $inject = ['$scope', '$http', 'Main', 'Authentication'];
    constructor (){}
}
export = LoginController
angular.module('App').controller('Controller', LoginController.Controller);

Did I forget to inject something here to invoke the method?


Solution

  • The issue here is related to the fact, that the angular's $inject cannot profit from the Typescript require. These are independent features, they represent different concepts.

    The angular's [$inject][1], as a built-in Dependency Injection, can only inject, what was already registered. It does not have any access to Typescript objects - just to it's own (angular's) Object Factory.

    As the error says: unknown provider 'AuthenticationProvider', we have to call:

    angular.module('App')
      .factory('Authentication', [... its dependencies ...
          , (params) => new Authentication(params)]);
    

    Now, we do have Authentication ready in angular, and we can ask for that inside of our Controller

    The syntax could look like this:

    // module with Scope and Controller
    module LoginController
    {
      export interface UIMainScope extends ng.IScope 
      {
        login: (credential: any) => void;
      }
    
      export class Controller
      {
        // constructor, instantiating private members this.$scope ...
        constructor($scope: UIMainScope
           , $http :ng.IHttpService
           , Main: any
           , Authentication: any)
        ...
      }
    }
    
    // and finally pass it into angular as .controller()
    angular.module('App')
      .controller('Controller', [
         '$scope', '$http', 'Main', 'Authentication',
         ($scope, $http, Main, Authentication)  =>
         {
            return new LoginController.Controller($scope, $http, Main, Authentication);
         }
    ]);
    

    Finally: in cases, that Authentication provider will not profit from beeing initiated with Angular, we can use it as well. We do NOT have to regiester it at all. Just call require, and access its methods as well... but we have to skip the angular¨s $inject process...

    This maybe is not this case, but imagine some QueryStringBuilder... which could consume just a passed params in a method Builder.build(...)