【问题标题】:Implementing angularjs directives as classes in Typescript在 Typescript 中将 angularjs 指令实现为类
【发布时间】:2014-06-25 12:06:17
【问题描述】:

因此,在查看了 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;

但我不确定这是否正确或如何从那里继续(即如何将属性添加到范围)。

有人知道怎么解决吗? (希望,如果可能,不必恢复到函数)

谢谢,

【问题讨论】:

    标签: angularjs typescript


    【解决方案1】:

    将指令创建为类可能会有问题,因为您仍然需要使用工厂函数来包装其实例化。例如:

    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
    

    但实际上取决于您的用例,您可以使用多少重复的参数列表等。

    【讨论】:

      【解决方案2】:

      假设您所拥有的东西在没有孤立作用域的情况下工作,以下内容应该适用于孤立作用域:

      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");
              }
          }
      }
      

      【讨论】:

      • 太棒了!谢谢巴萨拉特!
      • 如何注册指令?
      • 再想一想,这是否会引起麻烦,因为指令工厂不是“新的”,而是作为函数调用的?特别是构造函数不会返回类以外的东西吗?
      • 我编写了一个实用程序,可用于在 TypeScript 中启用这种基于类的指令定义。 An example directive 可以找到解释here
      • 要注册这个,@bingle 解释如下:myModule.directive("angEnter", () => new MyDirective);
      【解决方案3】:

      这是我的建议:

      指令:

      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);
      

      装饰器(添加注入和生产指令对象):

      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

      【讨论】:

        【解决方案4】:

        最后我得到了一个指令作为类加继承。在派生指令中,我扩展了范围并定义了 templateUrl。 您可以覆盖基本指令中的任何方法 . key 是从构造函数返回指令的实例。Angularjs 调用没有 new 关键字的构造函数。在这种情况下,this 属于 window 类型 我换了几行来检查 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)));
            }
          }
        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-24
          • 1970-01-01
          • 2019-03-19
          • 2013-10-10
          • 1970-01-01
          • 1970-01-01
          • 2023-04-09
          • 2014-04-22
          相关资源
          最近更新 更多