J.J. Bocanegra J.J. Bocanegra - 3 months ago 22
TypeScript Question

Add a decorator to an angularjs directive with typescript

I created my own typescript decorator for Component and Inject and it looks like this

@Component(myModule, {
selector: 'selector',
templateUrl: 'template.html',
bindings: {
value: '=',
},
})
@Inject('service')
export class ComponentController {
value: string;

constructor(private service: Service) {}
}


Where the decorators code is

export const Component = function(moduleOrName: string | ng.IModule, options: any): Function {
return (controller: Function) => {
let module = typeof moduleOrName === 'string' ? angular.module(moduleOrName) : moduleOrName;
let component = angular.extend(options, { controller });
module.component(options.selector, component);
};
};

export const Inject = function(...injections: string[]): Function {
return (target: Function) => {
target.$inject = injections;
return target;
};
};


It works fine and now I want to do the same thing for a directive where I would need to use compile or link functions but I can't make it work

@Directive(app, {
selector: 'selector',
templateUrl: 'template.html',
scope: {
value: '=',
},
})
@Inject('service')
export class myDirective implements ng.IDirective {
value: string;

constructor(private service: Service) {}

compile(element: ng.IAugmentedJQuery) {
return this.service.compile(element);
}
}


The code of the Directive decorator is

export const Directive = function(moduleOrName: string | ng.IModule, options: any): Function {
return (directive: Function) => {
let module = typeof moduleOrName === 'string' ? angular.module(moduleOrName) : moduleOrName;
let prueba = angular.extend(options, { directive })
module.directive(options.selector, prueba);
};
};


And when I create the directive, it always shows this error in the angular library


Argument 'fn' is not a function, got Object


It could be done with a decorator or should I forget it and do it the usual way?

Thanks.

Answer

It should be

export const Directive = function(moduleOrName: string | ng.IModule, selector: string): Function {
    return (directive: any) => {
        let module = typeof moduleOrName === 'string' ? angular.module(moduleOrName) : moduleOrName;
        let factory = (...args: any[]) => {
            let options = {
                controller: function () {},
            };
            return angular.extend(new directive(...args), options);
        };
        factory.$inject = directive.$inject;
        module.directive(selector, factory);
    };
};

@Directive(app, 'selector')
@Inject('service')
export class MyDirective implements ng.IDirective {
    templateUrl = 'template.html';
    scope = {
        value: '=',
    };
    constructor(private service: Service) {}
    compile = function(element: ng.IAugmentedJQuery) {
        return this.service.compile(element);
    }
}