Как определить AngularJS factory с помощью класса TypeScript, который имеет параметры конструктора

Я хочу написать класс TypeScript, который получает параметр "префикс" в конструкторе, этот класс также нуждается в доступе к инъекции LogService.

Используя обычный JavaScript, вы должны сделать это следующим образом:

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

Итак, когда вы вводите этот factory в контроллер, вы можете инициировать его много раз (не нужно вводить LogService):

angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) {
    var foo = new LogWithPrefixFactory("My PREFIX");
    var foo = new LogWithPrefixFactory("My OTHER PREFIX");
}

Как бы вы определили этот factory в классе TypeScript? TypeScript классы не могут быть определены внутри функций... Этот класс должен иметь доступ к LogService, но он не может получить его в одном из инъекций.

Ответы

Ответ 1

Есть как минимум 2 варианта.

Первая опция, LogWithPrefixFactory предоставляет метод getInstance, который возвращает префиксный регистратор.

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

Что можно использовать в контроллере, например:

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

Завершить плункер здесь.

Второй вариант (аналогичный другому ответу), дайте Angular другую функцию, которая будет использоваться в качестве конструктора, которая вручную обрабатывает вставку конструктора LogService (лично мне не нравится static).

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

Что можно использовать в контроллере, например:

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

или даже:

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

LogWithPrefixFactory вводится в контроллер, но это не конструктор класса TypeScript, это промежуточная функция, которая возвращает фактический экземпляр класса после его "вручную" с помощью LogService.

Полный плунжер здесь.

Примечание. Эти плунжеры синхронно компилируют TypeScript в браузере. Я тестировал его только в Chrome. Нет гарантий, что они будут работать. Наконец, я вручную добавил небольшую часть angular.d.ts. Полный файл был очень большой, и мой прокси не допускал больших POST.

Ответ 2

Ниже приведен один из способов достижения этого:

class LogWithPrefixFactory {
    static LogService;
    constructor(prefix) {
        this.prefix = prefix;
    }

    log = function(txt) {
        // we have access to the injected LogService
        LogService.log(this.prefix, txt);
    }
}

angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) {
    LogWithPrefixFactory.LogService = LogService;
    return LogWithPrefixFactory;
}]);


angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) {
    var foo = new LogWithPrefixFactory("My PREFIX");
    var foo = new LogWithPrefixFactory("My OTHER PREFIX");
});

Rational: Вы действительно хотите статическое свойство в LogWithPrefixFactory (используя закрытие в JS), и вы хотите, чтобы он появился из Angular.

Ответ 3

Я достиг как ниже

module Dashboard {
    export class LayoutServiceFactory {
        static $inject = ["$q", "$http"];
        private q: ng.IQService;
        private http: ng.IHttpService;

        constructor(private $q: ng.IQService, private $http: ng.IHttpService) {
            this.q = $q;
            this.http = $http;
        }

        getDataFromServer(serviceUrl) {
            var deferred = this.q.defer();
            this.http.get(serviceUrl, null)
                .then(response => {

                    deferred.resolve((response) as any);

                });
            return deferred.promise;
        }

        static factory() {
            var instance = ($q: ng.IQService, $http: ng.IHttpService) =>
                new LayoutServiceFactory($q, $http);
            return instance;
        }
    }

    appModule.factory("LayoutService", LayoutServiceFactory.factory());
}

Ответ 4

вот как я это делаю

 namespace app {
             let app =angular.module('foo',[]);
               app.factory(factories);//for registering whatever is there in factories namespace

      }

 namespace app.factories {


 export class fooFactory {

    static $inject = ['fooHelperService']
    constructor(fooHelperService: services.fooHelperService) {

        return {

            fooFunc: () => {

               return 'hellow world'
            }
        }
    }
 }

}

Ответ 5

Это сработало для меня.

    namespace Services
    {
      export class MyService
      {
        constructor( protected $someService :any )
        {
          return this;
        }
      }
    }
    angular.module( 'myModule', [] ).factory( Services );

Ответ 6

Вы можете создать тип, который позволяет определить, что выглядит конструктор factory:

// Defining the factory

// THIS IS THE IMPORTANT PART!!
export type SelectorFactory = new (config: any) => Selector;

export class Selector {

    constructor(protected config: any, protected $http: ng.IHttpService) {
        // do some stuff
    }
}

angular.module('app')
    .factory('Selector', ($http: ng.IHttpService) => {
        // This is what the factory looks like to the end user
        return (config: any) => {
            return new Selector(config, $http);
        };
    });

// Using the factory
export class SampleCtrl {
    constructor(public SelectorFactory: SelectorFactory) {
        let config = { op: 1 };

        let selector: Selector = new SelectorFactory(config);
    }
}