因此,在看一下typescript中的angularjs指令的一些例子后,似乎大多数人同意在实现它们时使用函数而不是类。
我更愿意将它们作为一个类,并尝试按如下方式实现它们:
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");
}
}
}
现在这很好用。但是,我需要有一个具有某些属性的孤立范围,而我正在努力找出如何在类本身中包含它。
逻辑规定,因为我可以
public restrict: string;
public templateUrl: string;
我应该有类似的东西:
public scope;
但我不确定这是否正确或如何从那里继续(即如何将属性添加到范围)。
有谁知道如何解决这个问题? (希望如果可能的话,不必恢复功能)
谢谢,
答案 0 :(得分:23)
创建指令作为类可能会有问题,因为您仍需要使用工厂函数来包装其实例化。例如:
export class SomeDirective implements ng.IDirective {
public link = () => {
}
constructor() {}
}
什么不起作用
myModule.directive('someDirective', SomeDirective);
由于未使用' new'来调用指令。但只是被称为工厂功能。这将导致构造函数实际返回的问题。
什么(有警告)
myModule.directive(() => new SomeDirective());
如果您没有涉及任何IoC,这样可以正常工作,但是一旦开始引入注射剂,您必须为工厂函数和指令构造函数维护重复的参数列表。
export class SomeDirective implements ng.IDirective {
...
constructor(someService: any) {}
}
myModule.directive('someDirective', ['someService', (someService) => new SomeDirective(someService)]);
如果您喜欢这样,那么仍然是一个选项,但了解指令注册的实际消费方式非常重要。
另一种方法
angular实际预期的是一个指令工厂函数,所以类似于:
export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
return {
link: () => {...}
};
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
myModule.directive('someDirective', SomeDirectiveFactory);
这样可以允许使用$ inject注释,因为在这种情况下,angular需要它在工厂函数上。
您也可以始终从工厂函数返回您的类的实例:
export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
return new SomeDirective(someService);
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations
但实际上取决于您的使用案例,您可以使用多少参数列表重复等等。
答案 1 :(得分:20)
假设您在没有islolated范围的情况下工作,以下内容应该适用于隔离范围:
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");
}
}
}
答案 2 :(得分:2)
以下是我的建议:
指令:
import {directive} from '../../decorators/directive';
@directive('$location', '$rootScope')
export class StoryBoxDirective implements ng.IDirective {
public templateUrl:string = 'src/module/story/view/story-box.html';
public restrict:string = 'EA';
public scope:Object = {
story: '='
};
public link:Function = (scope:ng.IScope, element:ng.IAugmentedJQuery, attrs:ng.IAttributes):void => {
// console.info(scope, element, attrs, this.$location);
scope.$watch('test', () => {
return null;
});
};
constructor(private $location:ng.ILocationService, private $rootScope:ng.IScope) {
// console.log('Dependency injection', $location, $rootScope);
}
}
模块(寄存器指令......):
import {App} from '../../App';
import {StoryBoxDirective} from './../story/StoryBoxDirective';
import {StoryService} from './../story/StoryService';
const module:ng.IModule = App.module('app.story', []);
module.service('storyService', StoryService);
module.directive('storyBox', <any>StoryBoxDirective);
Decorator(添加inject和产生指令对象):
export function directive(...values:string[]):any {
return (target:Function) => {
const directive:Function = (...args:any[]):Object => {
return ((classConstructor:Function, args:any[], ctor:any):Object => {
ctor.prototype = classConstructor.prototype;
const child:Object = new ctor;
const result:Object = classConstructor.apply(child, args);
return typeof result === 'object' ? result : child;
})(target, args, () => {
return null;
});
};
directive.$inject = values;
return directive;
};
}
我考虑将module.directive(...)
,module.service(...)
移动到类文件,例如StoryBoxDirective.ts
但尚未作出决定和重构;)
您可以在此处查看完整的工作示例:https://github.com/b091/ts-skeleton
指令在这里:https://github.com/b091/ts-skeleton/blob/master/src/module/story/StoryBoxDirective.ts
答案 3 :(得分:0)
最后,我得到了一个指令作为类加继承。在派生指令中,我扩展了范围并定义了templateUrl。 您可以覆盖base指令中的任何方法 。 键是从构造函数返回的,指令的实例.Angularjs调用没有 new 关键字的构造函数。在这种情况下,此的类型为窗口 我用几行来检查 this 的实例类型,如果是窗口我创建一个新的指令实例。 (参见下面样本中的Activator类)
module Realty.directives {
export class BaseElementWithLabel implements ng.IDirective {
public restrict = 'E';
public replace = true;
public scope = {
label: '@',
model: '=',
icon: '@',
readonlyElement: '=',
remark: '@'
}
constructor(extendedScope) {
if (!(this instanceof Window)) {
extendedScope = extendedScope || {};
this.scope = angular.extend(this.scope, extendedScope);
}
}
link(scope: ng.IScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes, controller, transclude) {
scope['vm'] = {};
}
}
}
module Realty.directives {
export class textareaWithLabel extends Realty.directives.BaseElementWithLabel implements ng.IDirective {
templateUrl = 'directives/element-form/textarea-with-label-template.html';
constructor() {
super({
rows: '@'
});
return Realty.Activator.Activate(this, textareaWithLabel, arguments);
}
};
};
module Realty {
export class Activator {
public static Activate(instance: any, type, arguments) {
if (instance instanceof type) {
return instance;
}
return new(type.bind.apply(type, Array.prototype.concat.apply([null], arguments)));
}
}
}