一直想写关于 Angular 1.x 与 Angular 2.x (Angular 4.x 已发布) 区别的文章,方便 Angular 1.x 的用户快速的过渡到 Angular 2.x。在浏览文章的时候,发现 Todd Motto 大神,已经写了相关的系列文章。英文好的同学,建议直接阅读 Creating a custom filter (pipe) in Angular 原文哈,因为我并不打算完整地翻译。废话不多说,接下来我们开始进入正题。

目录

  • Angular 1.x

    • Creating a custom filter

    • Using filters in template

    • Passing arguments to filters

    • Filtering in Controllers with $filter()

  • Angular 2

    • Creating a custom pipe

    • Using pipes in template

    • Passing arguments to pipes

    • Filtering in Component classes with pipes

Angular 1.x

首先我们先来介绍一下,自定义过滤器要实现的功能,即要对以下模板中 {{}} 插值表达式中显示的数据进行格式化 (添加相应后缀)。

<!-- template code -->
<p>You came {{ '1' }}</p>
<p>You came {{ '2' }}</p>

格式化为:

<!-- when compiled -->
<p>You came 1st</p>
<p>You came 2nd</p>

了解完需求后,接下来我们开始来实现该功能。

Creating a custom filter

在 Angular 1.x 中,我们通过 filter() API 来创建自定义过滤器,具体代码如下:

const ordinal = () => {
  return value => {
    var suffix = ''; // 后缀名
    var last = value % 10;
    var specialLast = value % 100;
    if (!value || value < 1) {
      return value;
    }
    if (last === 1 && specialLast !== 11) {
      suffix = 'st';
    } else if (last === 2 && specialLast !== 12) {
      suffix = 'nd';
    } else if (last === 3 && specialLast !== 13) {
      suffix = 'rd';
    } else {
      suffix = 'th';
    }
    return value + suffix;
  };
};

angular
  .module('app') // 获取已创建的app模块
  .filter('ordinal',ordinal); // 使用filter API创建ordinal过滤器

Using filters in template

const app = {
  template: `
    <div>
      <ul>
        <li ng-repeat="num in $ctrl.numbers">
          {{ num | ordinal }}
        </li>
      </ul>
    </div>
  `,controller() {
    this.numbers = [
      1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
    ];
  }
};

angular
  .module('app')
  .component('app',app);

以上代码运行后的结果 - Plunker

Passing arguments to filters

为了让我们的 ordinal 过滤器更加灵活,它应该可以根据用户设置的参数,来动态的显示内容。接下来我们来看一下,Angular 1.x 中如何传递参数给过滤器。

const ordinal = () => {
  // passing another argument
  return (value,anotherValue) => {
    // do something with `value` and `anotherValue`
    // and return a new value
  };
};

angular
  .module('app')
  .filter('ordinal',ordinal);

更新后的 app 组件,如下:

const app = {
  template: `
    <div>
      <input ng-model="searchValue">
      <ul>
        <li ng-repeat="num in $ctrl.numbers">
          {{ num | ordinal:searchValue }}
        </li>
      </ul>
    </div>
  `,...
};

Filtering in Controllers with $filter()

除了在模板中使用 | 进行数据过滤外,我们还可以在 Controller 中使用 $filter 服务,进行数据处理。出于性能考虑,更推荐在 Controller 中使用 $filter 服务进行数据处理 (详细信息请参考 - Using Controller $filters to prevent $digest performance issues)。使用 $filter() 服务的具体示例如下:

const app = {
  template: `
    <div>
      <ul>
        <li ng-repeat="num in $ctrl.numbers">
          {{ num }}
        </li>
      </ul>
    </div>
  `,controller($filter) {
    let numbers = [
      1,20
    ];
    // iterate the existing collection before binding
    // returns a new filtered collection
    this.numbers = numbers.map(number => $filter('ordinal')(number));
  }
};

Angular 2

在 Angular 2 中,已经没有了 filter 过滤器,取而代之的是 pipe 管道。接下来我们来看一下,如何自定义管道。

Creating a custom pipe

ordinal.pipe.ts

import { Pipe,PipeTransform } from '@angular/core';

@Pipe({
    name: 'ordinal'
})
export class OrdinalPipe implements PipeTransform {
    transform(value: number): string {
        let suffix = '';
        let last = value % 10;
        let specialLast = value % 100;
        if (!value || value < 1) {
            return '' + value;
        }
        if (last === 1 && specialLast !== 11) {
            suffix = 'st';
        } else if (last === 2 && specialLast !== 12) {
            suffix = 'nd';
        } else if (last === 3 && specialLast !== 13) {
            suffix = 'rd';
        } else {
            suffix = 'th';
        }
        return value + suffix;
    }
}

通过以上示例,我们来总结一下自定义管道的步骤。自定义管道分为两个步骤:

  • 使用 @Pipe 装饰器定义 Pipe 的 Metadata 信息,如 Pipe 的名称 - 即 name 属性

  • 实现 PipeTransform 接口中定义的 transform 方法

Using pipes in template

为了能够在组件中使用已创建的 pipe (管道),我们必须在设置 @NgModule Metadata 信息时,在 declarations 属性中添加已创建的管道。

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'exe-app',template: `
    <div>
      <ul>
        <li *ngFor="let num of numbers">
          {{ num | ordinal }}
        </li>
      </ul>
    </div>
    `
})
export class AppComponent {
  numbers: Array<number>;

  constructor() {
    this.numbers = [
      1,20
    ];
  }
}

app.module.ts

import { NgModule } from '@angular/core';
import { browserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { OrdinalPipe } from './ordinal.pipe';

@NgModule({
  imports: [browserModule],declarations: [AppComponent,OrdinalPipe],bootstrap: [AppComponent]
})
export class AppModule { }

Passing arguments to pipes

在 Angular 2 中,我们也可以为管道添加参数,具体示例如下:

import { Pipe,PipeTransform } from '@angular/core';

@Pipe({
  name: 'ordinal'
})
export class OrdinalPipe implements PipeTransform {
  // passing another argument
  transform(value: number,anotherValue: string): string {
    // do something with `value` and `anotherValue`
    // and return a new value
  }
}

Filtering in Component classes with pipes

在 Angular 1.x 中,我们推荐在 Controller 中使用 $filter() 以提高程序的性能。在 Angular 2 中,我们同样也可以在组件类中,通过注入 pipe 实例,然后进行数据处理。具体示例如下:

import { Component } from '@angular/core';
import { OrdinalPipe } from './ordinal.pipe';

@Component({
  selector: 'exe-app',template: `
    <div>
      <ul>
        <li *ngFor="let num of numbers">
          {{ num }}
        </li>
      </ul>
    </div>
    `,providers: [OrdinalPipe]
})
export class AppComponent {
  numbers: Array<string>;

  constructor(private pipe: OrdinalPipe) {
    let numbers = [
      1,20
    ];
    this.numbers = numbers.map(number => this.pipe.transform(number));
  }
}

以上示例为了能够通过构造注入的方式,注入 OrdinalPipe 管道实例,我们必须在组件的 Metadata 信息中,定义 providers 属性。

我有话说

1.Angular 2 中要掌握管道,还需要了解哪些知识点?

要全面掌握 Angular 2 中的管道,你还需了解以下内容:

  • Angular 2 内建管道使用及分类

  • 管道链

  • 管道分类 (pure & impure)

  • @Pipe 装饰器与管道的执行 (可选)

详细内容请参考 - Angular 2 Pipe

2.在组件类中注入管道实例,如果没有在组件的 Metadata 信息中,定义 providers 属性会出现什么问题?(该问题,初学者可以先略过哈)

在回答这个问题之前,我们先来看一下未设置 providers 属性和已设置 providers 属性,编译后的代码:

未设置 providers 属性 :

View_AppComponent_Host0.prototype.injectorGetInternal =  // 注入器获取内部依赖项
  function(token,requestNodeIndex,notFoundResult) { 
    var self = this;
    if (((token === jit_AppComponent1) && (0 === requestNodeIndex))) { 
      return self._AppComponent_0_3.context; 
    }
    return notFoundResult;
};

已设置 providers 属性 :

View_AppComponent_Host0.prototype.injectorGetInternal =   // 注入器获取内部依赖项
  function(token,notFoundResult) {
    var self = this;
    if (((token === jit_OrdinalPipe1) && (0 === requestNodeIndex))) { 
      return self._OrdinalPipe_0_3; 
    }
    if (((token === jit_AppComponent2) && (0 === requestNodeIndex))) { 
      return self._AppComponent_0_4.context; 
    }
    return notFoundResult;
};

我们再来看一下未设置 providers 属性 时,控制台的输出结果:

为什么提示 No provider for OrdinalPipe,相信你已经知道了答案了。

Angular 2 Pipe vs Angular 1 Filter的更多相关文章

  1. 浅析HTML5页面元素及属性

    这篇文章主要介绍了浅析HTML5页面元素及属性,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. Swift之旅三函数与闭包

    用func来定义一个函数。试一试去掉day参数。你可以用嵌套函数来把又长又臭的代码组织一下。函数其实是闭包的一个特例。闭包内的代码可以访问到变量和函数必须是与闭包创建的范围是一致的,即便闭包是在另一个范围内执行——在讲嵌套函数时就说过这个例子了。试一试重写这个闭包,对所有奇数都返回0有几种方法可以更简明地写闭包。单行语句的闭包隐式返回语句中的值。作为最后一个参数传到函数里的闭包可以在括号后面马上出现。

  3. 对数组进行各种操作

    //:Playground-noun:aplacewherepeoplecanplayimportUIKit//声明、定义数组varnumbers=[1,2,216)">3,216)">5,216)">8]varstrings=["ios","android","java"]//数组长度numbers.countstrings.count//向数组中添加元素//向数组中追加元素numbers.ap

  4. 函数和闭包

    调用函数使用他的名字加上小括号中的参数列表。使用->分隔参数的名字和返回值类型。内嵌函数可以访问其定义所在函数的变量。你可以使用内嵌函数来组织代码,避免函数过长和过于复杂。这意味着函数可以返回另一个函数funcmakeIncrementer()->{funcaddOne->Int{return1+number}returnaddOne}varincrement=makeIncrementer()increment//一个函数可以接受其他函数作为参数funchasAnyMatches->Bool{forit

  5. swift2 函数

    输入输出参数为了实现在函数中修改传入的值,不仅仅改副本还要修改原值,可以将变量声明为输入输出参数嵌套函数这章中你所见到的所有函数都叫全局函数,它们定义在全局域中。你也可以把函数定义在别的函数体中,称作嵌套函数。默认情况下,嵌套函数是对外界不可见的,但是可以被他们封闭函数来调用。一个封闭函数也可以返回它的某一个嵌套函数,使得这个函数可以在其他域中被使用。

  6. Swift学习笔记之函数

    可以看看json-swiftlibrary中的应用。变量我们可以定义一个变量,这个变量的类型是函数类型:参数函数既然是类型的一种,那么显然也是可以作为参数传递的:返回值函数也是可以作为结果返回的。这个具体内容可以参见Swift方法的多面性中柯里化部分的内容。我们可以这样调用多返回值在Swift中我们可以利用tuple返回多个返回值。

  7. Swift - 函数

    函数参数与返回值在不同情况下的声明与实现:函数返回值Swit函数返回值支持任意数据类型,如:String、Int、数组、字典等。函数类型Swift的每个函数都有特定的函数类型,函数类型就像数据类型一样,即可用于定义变量,也可用作函数的形参类型,还可作为函数的返回值类型。使用函数类型在Swift中,使用函数类型就像使用其他类型一样。

  8. swift学习日志——可变参数

    可变参数一个可变参数可以接受零个或多个值。可变参数的传入值在函数体中变为此类型的一个数组。例如,一个叫做numbers的Double...型可变参数,在函数体内可以当做一个叫numbers的[Double]型的数组常量。这应该算是swift的一个Bug吧。swift还在完善中,相信不就将来会解决的。

  9. Swift 数组,字典,集合-Array,Set,Dictionary(二)

    数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集可变数组不可变数组数组元素的个数和访问数组元素追加数组元素在某个位置插入元素,Swift点语法删除元素判断数组是否为空遍历数组字典的定义字典访问键对应的值添加删除修改遍历字典单独遍历key和value

  10. swift3新路程8闭包的形式

    如果闭包是函数唯一的参数的话,可以省略小括号不写闭包的参数不仅可以使用参数名访问,我们也可以使用数字访问

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部