【问题标题】:Angular directive dependency injection - TypeScriptAngular 指令依赖注入 - TypeScript
【发布时间】:2015-08-28 21:48:24
【问题描述】:

似乎有很多方法可以在 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。

【问题讨论】:

  • 为什么要在 Angular 之上分层构建自己的模块?您从这层额外的复杂性、额外的全局状态和语义重复中获得什么好处?。

标签: angularjs typescript


【解决方案1】:

只需将$timeout 指定为工厂构造函数参数并传递即可。

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

【讨论】:

  • 就这么简单!谢谢!
【解决方案2】:

虽然有一个公认的答案,但我想给我两分钱.. 前段时间我在指令和过滤器(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。

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,并通过实现一个名为“ComponentRegistrator”的 Util 类解决了这个问题(灵感来自 cmets 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 this和static $inject。您必须按照 PSL 的描述指定注入:

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

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

    【讨论】:

      【解决方案4】:

      在我看来,稍微简单一点:

      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'];

      【讨论】:

        猜你喜欢
        • 2014-12-04
        • 2014-11-21
        • 1970-01-01
        • 2016-09-14
        • 2020-02-13
        • 2016-07-19
        • 2017-01-15
        • 2013-04-10
        • 2016-02-15
        相关资源
        最近更新 更多