简体   繁体   中英

Inject dependency to the angularjs directive using typescript

Lets say I have a simple angular directive that looks like this:

app.directive('setFocus', ['$timeout', function($timeout) {
return {
    restrict: 'AC',
    link: function(_scope, _element) {
        $timeout(function() {
            _element[0].focus();
        }, 0);
    }
};
}]);

How can I write this using Typescript and get the $timeout accesible within the link function? My example would look something like this:

/// <reference path="../../reference.ts"/>

class SetFocus{
    constructor() {
        var directive: ng.IDirective = {};
        directive.restrict = 'EA';
        directive.scope = { };        
        directive.link= function ($scope, $element, $attrs) {
        // How can I access $timeout here?

        }
        return directive;
    }
}

directives.directive('setFocus', [SetFocus]);

This might be a silly example but it is the principle I would like to get working, which is using injected dependencies in the angular link function.

Try this way:

class SetFocus implements ng.IDirective {
    //Directive settings
    restrict :string = 'EA';
    scope : any= {};
    //Take timeout argument in the constructor
    constructor(private $timeout: ng.ITimeoutService) {
    }

    link: ng.IDirectiveLinkFn = ($scope: ng.IScope, $element: ng.IAugmentedJQuery, $attrs: ng.IAttributes) => {
          //refer to the timeout
          this.$timeout(function() {
            $element[0].focus();
         }, 0);
    }
    //Expose a static func so that it can be used to register directive.
    static factory(): ng.IDirectiveFactory {
       //Create factory function which when invoked with dependencies by
       //angular will return newed up instance passing the timeout argument
        var directive: ng.IDirectiveFactory = 
              ($timeout:ng.ITimeoutService) => new SetFocus($timeout);
        //directive's injection list
        directive.$inject = ["$timeout"];
        return directive;
    }
}

directives.directive('setFocus', SetFocus.factory());

It could be a problem with the way you have it right now. Because directive factory is not newed up so its constructor will execute with this as global object. This way you don't end up having a huge constructor as well and can write it in proper class ey manner.

If you have many dependencies injected instead of repeating the arguments in the factory you could as well do:

  var directive: ng.IDirectiveFactory =
            (...args) => new (SetFocus.bind.apply(SetFocus, [null].concat(args)));

To avoid all the factory boilerplate (and the constructor array at all), I recently wrote a small library (currently as a test project), that make the definition of directives very simple (controller and template omitted here):

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

}

It uses decorators like @Directive and a customized version of the TypeScript compiler that make interfaces metadata available at runtime (so ng.IQService can be translated to '$q' and injected in the constructor array). No more app.directive(...) boilerplate: everything is done in decorators :) You can give a look at the sample application code here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM