Can somebody provide me with an example of how I can create an Angular Filter in TypeScript that uses dependency injection. At the bottom is what I currently have, which is
You can use classes to inject dependencies, just use the [] in the module and use method injection as below:
module Filters {
export class MyFilter {
public static Factory(injectableService: InjectableService) {
return function (input:any) {
// use injectableService to affect your input in desired way
return input;
}
}
}
angular.module('app')
.filter('myFilter', ['injectableService', MyFilter.Factory]);
First, you need to use angular.d.ts definition file.
Then, you simply do the following :
MyFilter.$inject = ["$log"];
function MyFilter ($log: ng.ILogService): Function {
return function(msg: string) {
$log.log("I'm injected!");
return msg;
};
}
angular.module("testModule").filter("MyFilter", MyFilter);
$inject
property is available in Function
thanks to these lines in angular.d.ts
:
// Support for painless dependency injection
interface Function {
$inject?: string[];
}
See https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/angularjs/angular.d.ts#L12
It's generally better to use a function
+module
instead of a class
when writing an Angular filter. You can structure the code like this:
function FriendlyDateFilter($filter) {
return function (s: string): string {
/* Your logic here */
}
/* Helper logic here */
}
module FriendlyDateFilter {
export var $inject = ['$filter'];
}
angular.module("ReadingLog").filter("FriendlyDateFilter", FriendlyDateFilter);
You could also place both FriendlyDateFilter
declarations inside another module
if you're trying to avoid adding too much to the global scope.
I had the same problem while writing my own DI system for AngularJs 1.3 & Typescript. To solve this I wrote a decorator that accepts a class that implements the following interface:
interface IFilter {
filter(value?: any, ...args): any;
}
and it registers the filter with the following code:
var filterFactory = (...args) => {
var filterObject = new target(...args);
if (typeof filterObject.filter === 'function') {
return filterObject.filter.bind(filterObject);
}
console.warn('Invalid filter: filter() method not found for:', filterName)
return function() { }; //dummy filter, so it won't break everything
};
var constructorArray: Array<any> = injector.resolveParamNames(target);
app.filter(filterName, constructorArray.concat(filterFactory));
My library uses a custom version of the TypeScript compiler, which is able to emit interface metadata that is used by injector.resolveParamNames
to build the classic constructor array like this one: ['$q', '$timeout', FilterFactory]
You can find my project here, and a sample of filter here