AngularJS Filter with TypeScript and injection

2019-02-17 13:33发布

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 working fine, but what I want to do is in is the function I want to have access to $filter, so that I can change the line return date.ToString() into $filter'date'. That way I use the built in date filter to show a nice friendly short date.

class FriendlyDateFilter {

    public static Factory() {
        return function (input): string {
            if (angular.isDate(input)) {
                var date: Date = input;
                var today = new Date();
                var days = Math.abs(getDaysBetweenDates(today, date));
                if (days < 7) {
                    var dayInWeek = date.getDay();
                    switch (dayInWeek) {
                        case 0:
                            return "Sunday";
                            break;
                        case 1:
                            return "Monday";
                            break;
                        case 2:
                            return "Tuesday";
                            break;
                        case 3:
                            return "Wednesday";
                            break;
                        case 4:
                            return "Thursday";
                            break;
                        case 5:
                            return "Friday";
                            break;
                        case 6:
                            return "Saturday";
                            break;
                    }
                } else {
                    return date.toString();
                }
            } else {
                return input;
            }
        }

        function getDaysBetweenDates(d0, d1) {
            var msPerDay = 8.64e7;

            // Copy dates so don't mess them up
            var x0: any = new Date(d0);
            var x1: any = new Date(d1);

            // Set to noon - avoid DST errors
            x0.setHours(12, 0, 0);
            x1.setHours(12, 0, 0);

            // Round to remove daylight saving errors
                return Math.round((x1 - x0) / msPerDay);
            }
        }

    }
}

angular.module("ReadingLog").filter("FriendlyDateFilter", FriendlyDateFilter.Factory);

4条回答
Deceive 欺骗
2楼-- · 2019-02-17 14:03

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.

查看更多
迷人小祖宗
3楼-- · 2019-02-17 14:03

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

查看更多
Viruses.
4楼-- · 2019-02-17 14:05

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

查看更多
女痞
5楼-- · 2019-02-17 14:12

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]);
查看更多
登录 后发表回答