How can I define an AngularJS factory using TypeScript class that has constructor parameters

angularjs, typescript

Solution

There are at least 2 options.

First option, have `LogWithPrefixFactory` provide a method `getInstance` that returns the prefixed logger.

module services {
  class LogService {
    $window: any;

    constructor($window: any) {
      this.$window = $window;
    }

    log(prefix: string, txt: string) {
      this.$window.alert(prefix + ' :: ' + txt);
    }
  }
  angular.module('services').service('LogService', ['$window', LogService]);


  export interface ILog {
    log: (txt) => void;
  }

  export class LogWithPrefixFactory {
    logService: LogService;

    constructor(logService: LogService) {
      this.logService = logService;
    }

    getInstance(prefix: string): ILog {
      return {
        log: (txt: string) => this.logService.log(prefix, txt);
      }
    }
  }

  angular.module('services').service('LogWithPrefixFactory', ['LogService', services.LogWithPrefixFactory]);
}

Which can be used in the controller like:

this.log1 = logWithPrefixFactory.getInstance("prefix1");
this.log2 = logWithPrefixFactory.getInstance("prefix2");

Complete plunker here.

Second option (similar to another answer), give Angular another function to be used as a constructor, which handles manually the `LogService` constructor injection (personally, I don't like `static`).

angular.module('services').service('LogWithPrefixFactory', ['LogService', function(logService) {
    return function LogWithPrefixFactory(prefix) {
      return new LogWithPrefix(prefix, logService);
    };
}]);

Which can be used in the controller like:

this.log1 = new LogWithPrefixFactory("prefix1");
this.log2 = new LogWithPrefixFactory("prefix2");

or even:

this.log1 = LogWithPrefixFactory("prefix1");
this.log2 = LogWithPrefixFactory("prefix2");

`LogWithPrefixFactory` is injected in the controller but it's not the TypeScript class constructor, it's the intermediate function which returns the actual instance of the class, after it has been "manually" injected with `LogService`.

Complete plunker here.

Note: These plunkers synchronously compile typescript on the browser. I have tested it only on Chrome. No guarantees that they'll work. Finally, I manually added a small part of angular.d.ts. Full file was very big and my proxy does not allow large POSTs.

Problem

I want to write a TypeScript class that gets a "prefix" parameter in the constructor, this class also needs access to a LogService inject. Using plain JavaScript you should do it like this: ``` angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) { var LogWithPrefixFactory = function(prefix) { this.prefix = prefix; } LogWithPrefixFactory.prototype.log = function(txt) { // we have access to the injected LogService LogService.log(this.prefix, txt); } return LogWithPrefixFactory; }]); ``` So when you inject this factory to a controller, you can initiate it many times like this (No need to inject the LogService): ``` angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) { var foo = new LogWithPrefixFactory("My PREFIX"); var foo = new LogWithPrefixFactory("My OTHER PREFIX"); } ``` How would you define this Factory in a TypeScript class? TypeScript classes can not be defined inside functions... This class should have access to the LogService, but it can't get it in one of the injects.

Original source