Как определить 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);
}
}