Implementando directivas de AngularJS como clases en TypeScript
Entonces, después de echar un vistazo a algunos de los ejemplos de directivas de AngularJS en TypeScript, parece que la mayoría de la gente está de acuerdo en usar funciones en lugar de clases al implementarlas.
Preferiría tenerlos como una clase e intenté implementarlos de la siguiente manera:
module directives
{
export class search implements ng.IDirective
{
public restrict: string;
public templateUrl: string;
constructor()
{
this.restrict = 'AE';
this.templateUrl = 'directives/search.html';
}
public link($scope: ng.IScope, element: JQuery, attributes: ng.IAttributes)
{
element.text("Hello world");
}
}
}
Ahora esto funciona bien. Sin embargo, necesito tener un ámbito aislado con algunos atributos y estoy teniendo dificultades para averiguar cómo incluir eso en la propia clase.
la lógica dicta que dado que puedo tener
public restrict: string;
public templateUrl: string;
Debería poder tener algo como:
public scope;
Pero no estoy seguro si esto es correcto o cómo continuar desde ahí (es decir, cómo agregar los atributos al alcance).
¿Alguien sabe cómo resolver esto? (esperemos, sin tener que recurrir a una función si es posible)
Gracias,
Respuesta #1
Crear directivas como clases puede ser problemático ya que todavía necesitas involucrar una función de fábrica para envolver su instanciación. Por ejemplo:
export class SomeDirective implements ng.IDirective {
public link = () => {
}
constructor() {}
}
Lo que no funciona
myModule.directive('someDirective', SomeDirective);
Dado que las directivas no se invocan usando 'new', sino que simplemente se llaman como funciones de fábrica, esto causará problemas con lo que su función constructora realmente devuelve.
Qué Significa (con Salvedades)
myModule.directive(() => new SomeDirective());
Esto funciona bien siempre que no tengas ningún IoC involucrado, pero una vez que comienzas a introducir inyectables, tienes que mantener listas de parámetros duplicadas para tu función de fábrica y tu constructor de directivas.
export class SomeDirective implements ng.IDirective {
...
constructor(someService: any) {}
}
myModule.directive('someDirective', ['someService', (someService) => new SomeDirective(someService)]);
Todavía es una opción si eso es lo que prefieres, pero es importante entender cómo se consume realmente el registro de la directiva.
Un enfoque alternativo
Lo que Angular espera realmente es una función fábrica de directivas, así que algo como:
export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
return {
link: () => {...}
};
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
myModule.directive('someDirective', SomeDirectiveFactory);
Esto tiene el beneficio de permitir el uso de anotaciones $inject ya que Angular lo necesita en la función fábrica en este caso.
También siempre podrías devolver una instancia de tu clase desde la función de fábrica:
export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
return new SomeDirective(someService);
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
Pero realmente depende de tu caso de uso, cuánta duplicación de listas de parámetros estás dispuesto a aceptar, etc.
Respuesta #2
Suponiendo que lo que tienes funciona sin un alcance aislado, lo siguiente debería funcionar con un alcance aislado:
module directives
{
export class search implements ng.IDirective
{
public restrict = 'AE';
public templateUrl = 'directives/search.html';
public scope = {
foo:'=',
bar:'@',
bas:'&'
};
public link($scope: ng.IScope, element: JQuery, attributes: ng.IAttributes)
{
element.text("Hello world");
}
}
}
