Angular指令依赖注入 - TypeScript

时间:2015-06-12 19:14:46

标签: angularjs typescript

似乎有很多方法可以在TypeScript中创建Angular指令。我唯一看到的是使用静态工厂函数:

module app {
    export class myDirective implements ng.IDirective {
        restrict: string = "E";
        replace: boolean = true;
        templateUrl: string = "my-directive.html";

        link: ng.IDirectiveLinkFn = (scope: ng.IScope, el: ng.IAugmentedJQuery, attrs: ng.IAttributes) => {
        };

        static factory(): ng.IDirectiveFactory {
            var directive: ng.IDirectiveFactory = () => new myDirective();
            return directive;
        }
    }

    angular.module("app")
        .directive("myDirective", myDirective.factory());
}

但是如果我需要注射东西,我不知道该怎么办。说我想要$ timeout:

module app {
    export class myDirective implements ng.IDirective {
        restrict: string = "E";
        replace: boolean = true;
        templateUrl: string = "my-directive.html";

        constructor(private $timeout: ng.ITimeoutService) {
        }

        link: ng.IDirectiveLinkFn = (scope: ng.IScope, el: ng.IAugmentedJQuery, attrs: ng.IAttributes) => {
            // using $timeout
             this.$timeout(function (): void {
             }, 2000);
        }

        static factory(): ng.IDirectiveFactory {
            var directive: ng.IDirectiveFactory = () => new myDirective(); // Uhoh! - What's goes here?
            directive.$inject = ["$timeout"];
            return directive;
        }
    }

    angular.module("app")
        .directive("myDirective", myDirective.factory());
}

如上所示,我不确定如何调用myDirective构造函数并传入$ timeout。

4 个答案:

答案 0 :(得分:4)

只需指定$timeout作为工厂构造函数参数并传递它。

   static factory(): ng.IDirectiveFactory {
        var directive: ng.IDirectiveFactory = 
                       ($timeout:ng.ITimeoutService) => new myDirective($timeout); 
        directive.$inject = ["$timeout"];
        return directive;
    }

答案 1 :(得分:0)

虽然有一个公认的答案,但我想给我两分钱。 前段时间我对指令有同样的问题,但也有过滤器(Angular注册过滤器工厂),所以我决定围绕标准类型定义构建一个小型库,允许我写这样的东西(控制和模板代码是省略):

@Directive('userRank')
export class UserRankDirective implements ng.IDirective {

    controller = UserRankDirectiveController;
    restrict = 'A';
    template = template;
    //controllerAs: 'ctrl', set as default
    replace = true;
    scope = {
        user: '=userRank'
    }

    constructor($q: ng.IQService) {
        console.log('Q service in UserRankDirective:', $q);
    }

}

为了实现这一点,我必须自定义TypeScript代码发射器,现在它生成接口元数据(ng.IQService在运行时可用并映射到构造函数数组中的'$q';元数据由@Directive装饰器使用,该装饰器使用this code在应用程序模块中注册指令。 您可以查看示例应用程序代码here

答案 2 :(得分:0)

我遇到了同样的问题并通过实现名为“ComponentRegistrator”的Util类(受评论on this page启发)解决了这个问题:

/// <reference path="../../../Typings/tsd.d.ts"/>
module Common.Utils {
    "use strict";

    export class ComponentRegistrator {
        public static regService(app: ng.IModule, name: string, classType: Function) {
            return app.service(name, classType);
        }

        public static regController(app: ng.IModule, name: string, classType: Function) {
            var factory: Function = Component.reg(app, classType);
            return app.controller(name, factory);
        }

        public static regDirective(app: ng.IModule, name: string, classType: Function) {
            var factory: Function = Component.reg(app, classType);
            return app.directive(name, <ng.IDirectiveFactory>factory);
        }

        private static reg<T extends ng.IDirective>(app: ng.IModule, classType: Function) {
            var factory: Function = (...args: any[]): T => {
                var o = {};
                classType.apply(o, args) || console.error("Return in ctor missing!");
                return <T> o;
            };
            factory.$inject = classType.$inject || [];
            return factory;
        }
    }
}

这可以例如使用如下:

/// <reference path="../../../Typings/tsd.d.ts"/>
///<reference path="../../Common/Utils/Component.ts"/>

module Sample {
    "use strict";

    class SampleDirective implements ng.IDirective {
        public static $inject: string[] = [];

        public templateUrl: string;
        public scope: {};
        public restrict: string;
        public require: string;
        public link: ng.IDirectiveLinkFn;

        constructor() {
            this.templateUrl = "/directives/sampleDirective.html";
            this.restrict = "A";
            this.scope = {
                element: "=",
            };
            this.link = this.linker;
            return this; // important!
        }

        private linker = (scope: IExpressionConsoleScope): void => {
            // ...
        };
    }

    ComponentRegistrator.regDirective(app, "directiveName", SampleDirective);
}

注意构造工具中的return thisstatic $inject。您必须按PSL所述指定注入:

// ...
class SampleDirective implements ng.IDirective {
    public static $inject: string[] = ["$timeout"];
// ...
constructor(private $timeout:ng.ITimeoutService) {
// ...

这样可以避免重复工厂方法,并且您可以始终使用相同的模式......

答案 3 :(得分:0)

在我看来更简单一点:

&#13;
&#13;
export var SomeComponent = ($timeout: any): ng.IDirective => {
  return {
    controller,
    controllerAs: 'vm',
    restrict: 'E',
    templateUrl: 'components/someTemplate/someTemplate.html',
    scope: {
      someAttribute: '@'
    },
    link: {
      post: (scope, elem, attr, ctrl) => {
        console.log('Should see this here:', $timeout);
      }
    }
  };
}

SomeComponent.$inject = ['$timeout'];
&#13;
&#13;
&#13;