使用 TypeScript 和注入的 AngularJS 过滤器

Posted

技术标签:

【中文标题】使用 TypeScript 和注入的 AngularJS 过滤器【英文标题】:AngularJS Filter with TypeScript and injection 【发布时间】:2015-09-15 02:00:35 【问题描述】:

谁能给我一个例子,说明我如何在 TypeScript 中创建一个使用依赖注入的 Angular 过滤器。底部是我目前拥有的,工作正常,但我想要做的是我想要访问 $filter 的函数,以便我可以将行 return date.ToString() 更改为 $filter '日期'。这样我就可以使用内置的日期过滤器来显示一个友好的短日期。

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

【问题讨论】:

将 $filter 作为参数添加到工厂函数?这就是你在 JS 中的做法。 是的,我认为这是我需要的,但我还需要在某处/以某种方式使用 $inject,这就是我不明白该怎么做。 在 JS 中,你会做FriendlyDateFilter.Factory.$inject = ['$filter']。或者你什么都不做,只在构建过程中使用 ng-annotate。 我不知道在我的 TypeScript 类中我可以把它放在哪里。 【参考方案1】:

你可以使用类来注入依赖,只需要在模块中使用 [] 并使用方法注入如下:

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]);

【讨论】:

【参考方案2】:

首先,您需要使用angular.d.ts definition file。

然后,您只需执行以下操作:

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 属性在Function 中可用,这要归功于angular.d.ts 中的这些行:

// Support for painless dependency injection
interface Function 
  $inject?: string[];

见https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/angularjs/angular.d.ts#L12

【讨论】:

【参考方案3】:

我在为 AngularJs 1.3 和 Typescript 编写自己的 DI 系统时遇到了同样的问题。为了解决这个问题,我编写了一个装饰器,它接受一个实现以下接口的类:

interface IFilter 
    filter(value?: any, ...args): any;

它使用以下代码注册过滤器:

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

我的库使用自定义版本的 TypeScript 编译器,它能够发出接口元数据,injector.resolveParamNames 使用该元数据来构建像这样的经典构造函数数组:['$q', '$timeout', FilterFactory]

您可以找到我的项目here,以及过滤器示例here

【讨论】:

【参考方案4】:

在编写 Angular 过滤器时,通常最好使用 function+module 而不是 class。您可以像这样构造代码:

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

如果您想避免向全局范围添加太多内容,也可以将两个 FriendlyDateFilter 声明放在另一个 module 中。

【讨论】:

为什么不简单地使用FriendlyDateFilter.$inject = ['$filter'] 而不是使用带有导出变量的模块? 你可以使用 FriendlyDateFilter['$inject'] = ... 但 TypeScript 不允许在没有某种声明的情况下使用点语法 它将与来自DefiniteTyped 的angular.d.ts 一起使用,请参阅github.com/DefinitelyTyped/DefinitelyTyped/blob/master/… @adripanico 如果您觉得我的回答有用,请点赞:) 我做到了!再次感谢。

以上是关于使用 TypeScript 和注入的 AngularJS 过滤器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 TypeScript 静态注入器模式注入`$rootScope`?

在 Angular2 中使用生成的 Swagger TypeScript Rest Client

AngularJS 和 Typescript - 注入其他服务的服务未定义

Typescript - 如何访问通过命名空间声明的类?

在 typescript / angular2 环境和后端的 nodejs 中设置持久会话时遇到问题

在 NestJS 中使用依赖注入导入 TypeScript 模块