Implementera AngularJS-direktiv som klasser i Typescript


Så efter att ha tittat på några exempel på AngularJS-direktiv i TypeScript verkar de flesta vara överens om att använda funktioner istället för klasser när man implementerar dem.

Jag skulle föredra att ha dem som en klass och försökte implementera dem på följande sätt:

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 fungerar detta bra. Men jag behöver ha ett isolerat omfång med några attribut och jag har svårt att lista ut hur man inkluderar det i själva klassen.

logiken dikterar att eftersom jag kan ha

public restrict: string;
public templateUrl: string;

Jag borde kunna ha något liknande:

public scope;

Men jag är inte säker på om detta är korrekt eller hur man går vidare därifrån (dvs hur man lägger till attributen i scopet).

Någon som vet hur man löser det här? (förhoppningsvis utan att behöva gå tillbaka till en funktion om möjligt)

Tack,

Svar #1

Att skapa direktiv som klasser kan vara problematiskt eftersom du fortfarande behöver använda en fabriksfunktion för att omsluta dess instansiering. Till exempel:

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

    constructor() {}
}

Vad som inte fungerar

myModule.directive('someDirective', SomeDirective);

Eftersom direktiv inte anropas med 'new' utan bara kallas som fabriksfunktioner. Detta kommer att orsaka problem med vad din konstruktörsfunktion faktiskt returnerar.

Vad betyder (med förbehåll)

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

Detta fungerar bra förutsatt att du inte har någon IoC involverad, men när du börjar introducera injicerbara måste du upprätthålla dubblettpostlistor för din fabriksfunktion och din direktivkonstruktor.

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

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

Fortfarande ett alternativ om det är det du föredrar, men det är viktigt att förstå hur direktivregistreringen faktiskt används.

Ett alternativt tillvägagångssätt

Det som faktiskt förväntas av Angular är en direktivfabrikfunktion, alltså något som:

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

myModule.directive('someDirective', SomeDirectiveFactory);

Detta har fördelen att det tillåter användning av $inject-anteckningar eftersom Angular behöver det på fabriksfunktionen i det här fallet.

Du kan alltid också returnera en instans av din klass från fabriksfunktionen:

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

Men det beror verkligen på ditt användningsfall, hur mycket duplicering av parametrar du är okej med, osv.

Svar #2

Förutsatt att det du har fungerar utan ett isolerat scope, bör följande fungera med ett isolerat 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");
        }
    }
}

Relaterade artiklar