¿Cómo puedo definir una fábrica de AngularJS usando una clase de TypeScript que tenga parámetros en el constructor?
Quiero escribir una clase de TypeScript que reciba un parámetro "prefix" en el constructor, esta clase también necesita acceso a un LogService inyectado.
Usando JavaScript puro deberías hacerlo así:
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;
}]);
Entonces, cuando inyectas esta fábrica en un controlador, puedes iniciarla muchas veces así (No es necesario inyectar el LogService):
angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) {
var foo = new LogWithPrefixFactory("My PREFIX");
var foo = new LogWithPrefixFactory("My OTHER PREFIX");
}
¿Cómo definirías esta fábrica en una clase de TypeScript? Las clases de TypeScript no se pueden definir dentro de funciones... Esta clase debería tener acceso al LogService, pero no puede obtenerlo en uno de los inyectables.
Respuesta #1
La siguiente es una manera de lograr esto:
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");
});
Racional: Básicamente quieres una propiedad estática en un LogWithPrefixFactory (usando un cierre en JS), y quieres que provenga de Angular.
Respuesta #2
Hay al menos 2 opciones.
Primera opción, hacer que LogWithPrefixFactory proporcione un método getInstance que devuelva el registrador con prefijo.
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]);
}
Que se puede usar en el controlador como:
this.log1 = logWithPrefixFactory.getInstance("prefix1");
this.log2 = logWithPrefixFactory.getInstance("prefix2");
Completa el plunker aquí.
Segunda opción (similar a otra respuesta), darle a Angular otra función para que se use como constructor, que maneje manualmente la inyección del constructor de LogService (personalmente, no me gusta static).
angular.module('services').service('LogWithPrefixFactory', ['LogService', function(logService) {
return function LogWithPrefixFactory(prefix) {
return new LogWithPrefix(prefix, logService);
};
}]);
Que se puede usar en el controlador como:
this.log1 = new LogWithPrefixFactory("prefix1");
this.log2 = new LogWithPrefixFactory("prefix2");
o incluso:
this.log1 = LogWithPrefixFactory("prefix1");
this.log2 = LogWithPrefixFactory("prefix2");
LogWithPrefixFactory se inyecta en el controlador, pero no es el constructor de la clase de TypeScript, es la función intermedia que devuelve la instancia real de la clase, después de que ha sido inyectada "manualmente" con LogService.
Completa el plunker aquí.
Nota: Estos plunkers compilan TypeScript de manera sincrónica en el navegador. Solo lo he probado en Chrome. No hay garantías de que funcionen. Finalmente, agregué manualmente una pequeña parte de angular.d.ts. El archivo completo era muy grande y mi proxy no permite POSTs grandes.
