Stack: Typescript 1.7 + Angular 1.49
Summary:
I have a directive. I want to $inject
angular's $timeout
service. It works fine in the directive's controller function, but not in the link function. What am I missing?
Questions:
- What did I do wrong?
- Is there a better way to
$inject
the$timeout
dependency? - Why will the
$timeout
service work in the directive's controller but not the link?
MyDirective.ts:
module app.directives {
export class MyDirective {
priority = 0;
restrict = 'E';
templateUrl = 'template.html';
scope = {
'items': '='
};
controller = MyController;
link = MyLink;
static $inject = ['$timeout'];
constructor(private $timeout:ng.ITimeoutService) {
}
}
function MyController($scope:ng.IScope, $timeout:ng.ITimeoutService) {
console.log("controller", $timeout); // function timeout(fn,delay,invokeApply){ the guts here }
$timeout(function () {
console.log("This works fine");
},3000);
}
function MyLink(scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, $timeout:ng.ITimeoutService) {
console.log("link to", $timeout); // MyController {}
$timeout(function () {
console.log("This throws the error, TypeError: $timeout is not a function");
},3000);
}
}
Connecting it in directives.ts:
module app.directives {
angular.module('app').directive('MyDirective',['$timeout',($timeout:ng.ITimeoutService) => new MyDirective($timeout) ]);
}
app.ts
module app {
angular.module('app', []);
}
What hasn't worked:
- Using
this.$timeout
in MyLink, with or without including$timeout
in the parameters. - I've found several articles and examples that I've tried to make sure I'm following the logic of in my app but can't seem to get it.
Final notes
- Typescript-Angular is still new and there are so many best practices that are far from being defined. Part of my team's project is finding some of those.
- We have been working on this general structure for a while, so unless there's a pelling reason, please refrain from suggestions that I change the structure of everything too much.
Stack: Typescript 1.7 + Angular 1.49
Summary:
I have a directive. I want to $inject
angular's $timeout
service. It works fine in the directive's controller function, but not in the link function. What am I missing?
Questions:
- What did I do wrong?
- Is there a better way to
$inject
the$timeout
dependency? - Why will the
$timeout
service work in the directive's controller but not the link?
MyDirective.ts:
module app.directives {
export class MyDirective {
priority = 0;
restrict = 'E';
templateUrl = 'template.html';
scope = {
'items': '='
};
controller = MyController;
link = MyLink;
static $inject = ['$timeout'];
constructor(private $timeout:ng.ITimeoutService) {
}
}
function MyController($scope:ng.IScope, $timeout:ng.ITimeoutService) {
console.log("controller", $timeout); // function timeout(fn,delay,invokeApply){ the guts here }
$timeout(function () {
console.log("This works fine");
},3000);
}
function MyLink(scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, $timeout:ng.ITimeoutService) {
console.log("link to", $timeout); // MyController {}
$timeout(function () {
console.log("This throws the error, TypeError: $timeout is not a function");
},3000);
}
}
Connecting it in directives.ts:
module app.directives {
angular.module('app').directive('MyDirective',['$timeout',($timeout:ng.ITimeoutService) => new MyDirective($timeout) ]);
}
app.ts
module app {
angular.module('app', []);
}
What hasn't worked:
- Using
this.$timeout
in MyLink, with or without including$timeout
in the parameters. - I've found several articles and examples that I've tried to make sure I'm following the logic of in my app but can't seem to get it.
Final notes
- Typescript-Angular is still new and there are so many best practices that are far from being defined. Part of my team's project is finding some of those.
- We have been working on this general structure for a while, so unless there's a pelling reason, please refrain from suggestions that I change the structure of everything too much.
2 Answers
Reset to default 6Link functions are not executed directly from directive instance, hence you wont get this
as Directive's config instance (which you instantiate via new
operator). Also you cannot inject anything to the link function (that is what directive constructor is for) unlike the controller constructor, the arguments to the link function are automatically passed in by the directive execution logic. You could use an arrow operator to resolve this issue.
Example:
export class MyDirective {
priority = 0;
restrict = 'E';
templateUrl = 'template.html';
scope = {
'items': '='
};
controller = MyController;
link:ng.IDirectiveLinkFn = (scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes) => {
//Here
this.$timeout(function () {
},3000);
};
constructor(private $timeout:ng.ITimeoutService) {
}
}
Or you could bind the context using function.bind. i.e link = MyLink;
and access the $timeout
using this.$timeout
.
If interseted you could take a look at creating some syntactic sugars by using experimental decorators for directives or you could try exploring something like this. However (just my opinion) using a class for directive config seems to be an overkill, you might as well just use a function with static inject.
Link function 4th parameter is the controller instance him self.
If you want to do it you should do something like:
module app.directives {
export class MyDirective {
link = MyLink;
static $inject = ['$timeout'];
constructor(public $timeout:ng.ITimeoutService) {
}
}
function MyLink(scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, ctrl:any) {
ctrl.$timeout(function () {
console.log("This throws the error, TypeError: $timeout is not a function");
},3000);
}
}
I know that this is not elegant but I have hard time finding a better solution, what do you think?