Angular 指令依赖注入 - TypeScript
Posted
技术标签:
【中文标题】Angular 指令依赖注入 - TypeScript【英文标题】:Angular directive dependency injection - 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 之上分层构建自己的模块?您从这层额外的复杂性、额外的全局状态和语义重复中获得什么好处?。 【参考方案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'];
【讨论】:
以上是关于Angular 指令依赖注入 - TypeScript的主要内容,如果未能解决你的问题,请参考以下文章