Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

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.

share|improve this question
up vote 5 down vote accepted

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)));
share|improve this answer

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.