Vraag Implementeren van angularjs-richtlijnen als klassen in Typescript


Dus na het bekijken van enkele voorbeelden van angularjs-richtlijnen in typoscript, lijkt het erop dat de meeste mensen ermee instemmen om functies te gebruiken in plaats van klassen bij het implementeren ervan.

Ik zou ze het liefst als een klasse hebben en ze als volgt proberen te implementeren:

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

        }
    }
} 

Nu werkt dit prima. Ik moet echter een geïsoleerde scope hebben met enkele attributen en ik heb moeite om erachter te komen hoe ik dat in de klasse zelf moet opnemen.

logica dicteert dat sinds ik kan hebben

public restrict: string;
public templateUrl: string;

Ik zou in staat moeten zijn om iets te hebben als:

public scope;

Maar ik weet niet zeker of dit correct is of hoe ik van daaruit verder kan gaan (dus hoe ik de attributen aan het bereik kan toevoegen).

Weet iemand hoe dit op te lossen? (hopelijk zonder terug te keren naar een functie indien mogelijk)

Bedankt,


16
2018-05-08 07:59


oorsprong


antwoorden:


Ervan uitgaande dat wat je hebt werkt zonder een geanonimiseerde scope, zou het volgende moeten werken met een geïsoleerde scope:

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

20
2018-05-08 08:57



Het maken van richtlijnen als klassen kan problematisch zijn omdat u nog steeds een fabrieksfunctie moet gebruiken om de instantiatie ervan om te zetten. Bijvoorbeeld:

export class SomeDirective implements ng.IDirective {
    public link = () => {
    }

    constructor() {}
}

Wat niet werkt

myModule.directive('someDirective', SomeDirective);

Omdat richtlijnen niet worden aangeroepen met 'nieuw', maar gewoon worden opgeroepen als fabrieksfuncties. Dit zal problemen veroorzaken met wat uw constructorfunctie eigenlijk terugkrijgt.

Wat doet (met kanttekeningen)

myModule.directive(() => new SomeDirective());

Dit werkt goed, mits je geen IoC hebt, maar als je injectables gaat introduceren, moet je dubbele parameterlijsten bijhouden voor je fabrieksfunctie en je richtlijncontructor.

export class SomeDirective implements ng.IDirective {
    ...
    constructor(someService: any) {}
}

myModule.directive('someDirective', ['someService', (someService) => new SomeDirective(someService)]);

Nog steeds een optie als dat is wat u wilt, maar het is belangrijk om te begrijpen hoe de richtlijnregistratie daadwerkelijk wordt gebruikt.

Een alternatieve benadering

Het ding dat eigenlijk wordt verwacht door hoekig is een richtlijn fabrieksfunctie, dus iets als:

export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
   return {
     link: () => {...}
   };
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations

myModule.directive('someDirective', SomeDirectiveFactory);

Dit heeft het voordeel dat u $ inject-annotaties kunt gebruiken, omdat hoekig in dit geval de fabrieksfunctie nodig heeft.

U kunt ook altijd een exemplaar van uw klasse uit de fabrieksfunctie retourneren:

export var SomeDirectiveFactory = (someService: any): ng.IDirective => {
   return new SomeDirective(someService);
}
SomeDirectiveFactory.$inject = ['someService']; //including $inject annotations

Maar hangt echt af van uw use-case, hoeveel duplicatie van parameterlijsten waar u mee in orde bent, etc.


22
2017-11-07 17:03



Dit is mijn voorstel:

Richtlijn:

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

}

Module (registersrichtlijn ...):

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 (voegt object voor injecteren en produceren toe):

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

Ik denk aan bewegen module.directive(...), module.service(...) naar klassenbestanden, b.v. StoryBoxDirective.ts  maar heeft nog geen beslissing en refactor genomen;)

U kunt hier een volledig werkvoorbeeld bekijken: https://github.com/b091/ts-skeleton

Richtlijn is hier: https://github.com/b091/ts-skeleton/blob/master/src/module/story/StoryBoxDirective.ts


2
2017-08-21 14:54



Hier kreeg ik eindelijk een richtlijn als klasse plus erfenis. In de afgeleide richtlijn breid ik het bereik uit plus definieer ik de templateUrl. U kunt alle methoden van de basisrichtlijn overschrijven . De sleutel was om terug te keren van constructor de instantie van de richtlijn. Angularjs roept constructor zonder nieuwe trefwoord. In dit geval deze is van het type venster Ik heb een paar regels ingepakt om het exemplaartype te controleren deze en in geval van venster maak ik een nieuw exemplaar van een richtlijn. (Zie Activator-klasse uit onderstaande voorbeeld)

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


0
2018-02-28 18:15