如何将过滤器应用于* ngFor?

时间:2015-12-08 19:30:31

标签: angular typescript

显然,Angular 2将使用管道而不是Angular1中的过滤器以及ng-for来过滤结果,尽管实现似乎仍然模糊,没有明确的文档。

即可从以下角度查看我想要实现的目标

<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>

如何使用管道实现?

23 个答案:

答案 0 :(得分:304)

基本上,您编写了一个管道,然后可以在*ngFor指令中使用。

在您的组件中:

filterargs = {title: 'hello'};
items = [{title: 'hello world'}, {title: 'hello kitty'}, {title: 'foo bar'}];

在模板中,您可以将字符串,数字或对象传递给管道以用于过滤:

<li *ngFor="let item of items | myfilter:filterargs">

在你的烟斗中:

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

@Pipe({
    name: 'myfilter',
    pure: false
})
export class MyFilterPipe implements PipeTransform {
    transform(items: any[], filter: Object): any {
        if (!items || !filter) {
            return items;
        }
        // filter items array, items which match and return true will be
        // kept, false will be filtered out
        return items.filter(item => item.title.indexOf(filter.title) !== -1);
    }
}

请记住在app.module.ts注册您的管道;您不再需要在@Component

中注册管道
import { MyFilterPipe } from './shared/pipes/my-filter.pipe';

@NgModule({
    imports: [
        ..
    ],
    declarations: [
        MyFilterPipe,
    ],
    providers: [
        ..
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Here's a Plunker演示使用自定义过滤器管道和内置切片管来限制结果。

请注意(正如几位评论员指出的那样)there is a reason为什么Angular中没有内置的过滤管道。

答案 1 :(得分:68)

很多人都有很好的方法,但这里的目标是通用并定义一个数组管道,它在与* ngFor的关系中非常可重用。

callback.pipe.ts (不要忘记将其添加到模块的声明数组中)

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

@Pipe({
    name: 'callback',
    pure: false
})
export class CallbackPipe implements PipeTransform {
    transform(items: any[], callback: (item: any) => boolean): any {
        if (!items || !callback) {
            return items;
        }
        return items.filter(item => callback(item));
    }
}

然后在您的组件中,您需要实现具有以下签名的方法(item:any)=&gt; boolean ,在我的例子中,我称之为filterUser,用于过滤用户年龄大于18岁的情况。

您的组件

@Component({
  ....
})
export class UsersComponent {
  filterUser(user: IUser) {
    return !user.age >= 18
  }
}

最后但并非最不重要的是,您的HTML代码将如下所示:

您的HTML

<li *ngFor="let user of users | callback: filterUser">{{user.name}}</li>

正如您所看到的,此管道在所有数组中都非常通用,例如需要通过回调过滤的项目。在我的案例中,我发现它对于* ng类似场景非常有用。

希望这有帮助!!!

codematrix

答案 2 :(得分:29)

简化方式(由于性能问题仅在小型阵列上使用。在大型阵列中,您必须通过代码手动制作过滤器):

请参阅:https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

@Pipe({
    name: 'filter'
})
@Injectable()
export class FilterPipe implements PipeTransform {
    transform(items: any[], field : string, value : string): any[] {  
      if (!items) return [];
      if (!value || value.length == 0) return items;
      return items.filter(it => 
      it[field].toLowerCase().indexOf(value.toLowerCase()) !=-1);
    }
}

用法:

<li *ngFor="let it of its | filter : 'name' : 'value or variable'">{{it}}</li>

如果您使用变量作为第二个参数,请不要使用引号。

答案 3 :(得分:24)

这是我在不使用管道的情况下实现的。

component.html

<div *ngFor="let item of filter(itemsList)">

component.ts

@Component({
....
})
export class YourComponent {
  filter(itemList: yourItemType[]): yourItemType[] {
    let result: yourItemType[] = [];
    //your filter logic here
    ...
    ...
    return result;
  }
}

答案 4 :(得分:15)

我不确定它什么时候进来但他们已经制作了切片管来做到这一点。它也有很好的记录。

https://angular.io/docs/ts/latest/api/common/index/SlicePipe-pipe.html

<p *ngFor="let feature of content?.keyFeatures | slice:1:5">
   {{ feature.description }}
</p>

答案 5 :(得分:8)

您还可以使用以下内容:

<template ngFor let-item [ngForOf]="itemsList">
    <div *ng-if="conditon(item)"></div>
</template>

如果您的商品符合条件

,则只显示div

有关详细信息,请参阅angular documentation 如果您还需要索引,请使用以下命令:

<template ngFor let-item [ngForOf]="itemsList" let-i="index">
    <div *ng-if="conditon(item, i)"></div>
</template>

答案 6 :(得分:6)

Angular2中的管道与命令行上的管道类似。每个先前值的输出都被输入到管道之后的过滤器中,这样就可以很容易地链接过滤器:

<template *ngFor="#item of itemsList">
    <div *ngIf="conditon(item)">{item | filter1 | filter2}</div>
</template>

答案 7 :(得分:4)

我已经根据这里和其他地方的答案创建了一个傻瓜。

此外,我必须添加@Input的{​​{1}},@ViewChildElementRef,然后创建<input>来观察它。

Angular2搜索过滤器:PLUNKR(更新:plunker不再有效)

答案 8 :(得分:4)

对于此要求,我实施并发布通用组件。见

https://www.npmjs.com/package/w-ng5

使用此组件之前,请使用npm:

安装此软件包
npm install w-ng5 --save

之后,在app.module中导入模块

...
import { PipesModule } from 'w-ng5';

在下一步中,添加app.module的声明部分:

imports: [
  PipesModule,
  ...
]

使用示例

过滤简单字符串

<input type="text"  [(ngModel)]="filtroString">
<ul>
  <li *ngFor="let s of getStrings() | filter:filtroString">
    {{s}}
  </li>
</ul>

过滤复杂字符串 - 字段&#39;值&#39;在第2级

<input type="text"  [(ngModel)]="search">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.valor2', value: search}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

过滤复杂的字符串 - 中间字段 - &#39;值&#39;在第1级

<input type="text"  [(ngModel)]="search3">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.valor1', value: search3}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

过滤复杂数组简单字段&#39; Nome&#39;等级0

<input type="text"  [(ngModel)]="search2">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'nome', value: search2}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

在树木字段中过滤 - 字段&#39; Valor&#39; 2级或者Valor&#39; 1级或者Nome&#39;在0级

<input type="text"  [(ngModel)]="search5">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.valor2', value: search5}, {field:'n1.valor1', value: search5}, {field:'nome', value: search5}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

过滤不存在​​的字段 - &#39; Valor&#39;在不存在的3级

<input type="text"  [(ngModel)]="search4">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.n3.valor3', value: search4}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

此组件使用无限属性级别...

答案 9 :(得分:3)

管道是最好的方法。但是低于一个也可以。

<div *ng-for="#item of itemsList">
  <ng-container *ng-if="conditon(item)">
    // my code
  </ng-container>
</div>

答案 10 :(得分:1)

理想情况下,您应该为此创建angualr 2管道。但是你可以做到这一点。

b = map_new(a)

答案 11 :(得分:1)

这是我的代码:

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

@Pipe({
    name: 'filter'
})
@Injectable()
export class FilterPipe implements PipeTransform {
    transform(items: any[], field : string, value): any[] {
      if (!items) return [];
      if (!value || value.length === 0) return items;
      return items.filter(it =>
      it[field] === value);
    }
}

示例:

LIST = [{id:1,name:'abc'},{id:2,name:'cba'}];
FilterValue = 1;

<span *ngFor="let listItem of LIST | filter : 'id' : FilterValue">
                              {{listItem .name}}
                          </span>

答案 12 :(得分:1)

与Angular 6一起使用的用于过滤ngFor的简单解决方案,如下所示:

<span *ngFor="item of itemsList"  >
  <div *ngIf="yourCondition(item)">
    
    your code
    
  </div>
</span

跨度很有用,因为它并不固有地代表任何东西。

答案 13 :(得分:1)

我创建了以下管道,用于从列表中获取所需的项目。

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

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {

  transform(items: any[], filter: string): any {
    if(!items || !filter) {
      return items;
    }
    // To search values only of "name" variable of your object(item)
    //return items.filter(item => item.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1);

    // To search in values of every variable of your object(item)
    return items.filter(item => JSON.stringify(item).toLowerCase().indexOf(filter.toLowerCase()) !== -1);
  }

}

小写转换只是为了匹配不区分大小写的方式。 您可以在视图中使用它,如下所示: -

<div>
  <input type="text" placeholder="Search reward" [(ngModel)]="searchTerm">
</div>
<div>
  <ul>
    <li *ngFor="let reward of rewardList | filter:searchTerm">
      <div>
        <img [src]="reward.imageUrl"/>
        <p>{{reward.name}}</p>
      </div>
    </li>
  </ul>
</div>

答案 14 :(得分:1)

我喜欢用于特定于应用程序的过滤器的另一种方法是在组件上使用自定义只读属性,这允许您比使用自定义管道(IMHO)更干净地封装过滤逻辑。

例如,如果我想绑定到albumList并过滤searchText

searchText: "";
albumList: Album[] = [];

get filteredAlbumList() {
    if (this.config.searchText && this.config.searchText.length > 1) {
      var lsearchText = this.config.searchText.toLowerCase();
      return this.albumList.filter((a) =>
        a.Title.toLowerCase().includes(lsearchText) ||
        a.Artist.ArtistName.toLowerCase().includes(lsearchText)
      );
    }
    return this.albumList;
}

要在HTML中绑定,您可以绑定到只读属性:

<a class="list-group-item"
       *ngFor="let album of filteredAlbumList">
</a>

我发现特定于应用程序的专用过滤器比管道更好,因为它保持与过滤器相关的逻辑与组件。

管道可以更好地用于全局可重用的过滤器。

答案 15 :(得分:0)

使用component.ts文件中的@Pipe创建过滤器的第一步:

<强> your.component.ts

import { Component, Pipe, PipeTransform, Injectable } from '@angular/core';
import { Person} from "yourPath";

@Pipe({
  name: 'searchfilter'
})
@Injectable()
export class SearchFilterPipe implements PipeTransform {
  transform(items: Person[], value: string): any[] {
    if (!items || !value) {
      return items;
    }
    console.log("your search token = "+value);
    return items.filter(e => e.firstName.toLowerCase().includes(value.toLocaleLowerCase()));
  }
}
@Component({
  ....
    persons;

    ngOnInit() {
         //inicial persons arrays
    }
})

Person对象的数据结构:

<强> person.ts

export class Person{
    constructor(
        public firstName: string,
        public lastName: string
    ) { }
}

在html文件的视图中:

<强> your.component.html

    <input class="form-control" placeholder="Search" id="search" type="text" [(ngModel)]="searchText"/>
    <table class="table table-striped table-hover">
      <colgroup>
        <col span="1" style="width: 50%;">
        <col span="1" style="width: 50%;">
      </colgroup>
      <thead>
        <tr>
          <th>First name</th>
          <th>Last name</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let person of persons | searchfilter:searchText">
          <td>{{person.firstName}}</td>
          <td>{{person.lastName}}</td>
        </tr>
      </tbody>
    </table>

答案 16 :(得分:0)

基于上面提出的非常优雅的回调管道解决方案,可以通过允许传递额外的过滤器参数来进一步概括它。然后我们有:

<强> callback.pipe.ts

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

@Pipe({
  name: 'callback',
  pure: false
})
export class CallbackPipe implements PipeTransform {
  transform(items: any[], callback: (item: any, callbackArgs?: any[]) => boolean, callbackArgs?: any[]): any {
    if (!items || !callback) {
      return items;
    }
    return items.filter(item => callback(item, callbackArgs));
  }
}

<强>组件

filterSomething(something: Something, filterArgs: any[]) {
  const firstArg = filterArgs[0];
  const secondArg = filterArgs[1];
  ...
  return <some condition based on something, firstArg, secondArg, etc.>;
}

<强> HTML

<li *ngFor="let s of somethings | callback : filterSomething : [<whatWillBecomeFirstArg>, <whatWillBecomeSecondArg>, ...]">
  {{s.aProperty}}
</li>

答案 17 :(得分:0)

这是你的数组

products: any = [
        {
            "name": "John-Cena",
                    },
        {
            "name": "Brock-Lensar",

        }
    ];

这是你的ngFor循环 过滤方式:

<input type="text" [(ngModel)]='filterText' />
    <ul *ngFor='let product of filterProduct'>
      <li>{{product.name }}</li>
    </ul>

我正在使用filterProduct产品即时产品,因为我想保留原始数据。 这里模型_filterText用作输入框。当有任何更改时,setter函数将调用。 在setFilterText中调用performProduct,它将仅返回与输入匹配的结果。我使用小写字母不区分大小写。

filterProduct = this.products;
_filterText : string;
    get filterText() : string {
        return this._filterText;
    }

    set filterText(value : string) {
        this._filterText = value;
        this.filterProduct = this._filterText ? this.performProduct(this._filterText) : this.products;

    } 

    performProduct(value : string ) : any {
            value = value.toLocaleLowerCase();
            return this.products.filter(( products : any ) => 
                products.name.toLocaleLowerCase().indexOf(value) !== -1);
        }

答案 18 :(得分:0)

在谷歌搜索后,我遇到了df[df$x1 == 9 & df$x2 == 9,] 。 In将获取您的对象并将搜索词应用于所有对象属性以寻找匹配项。

答案 19 :(得分:0)

这是我在一段时间后创建的一个例子,其中包括一个有效的插件。它提供了一个过滤管道,可以过滤任何对象列表。您基本上只需在ngFor规范中指定属性和值{key:value}。

与@ NateMay的回复没什么不同,除了我用相对冗长的细节解释它。

在我的例子中,我使用这种标记过滤了用户在我的数组中对象的“label”属性输入的某些文本(filterText)上的无序列表:

<ul>
  <li *ngFor="let item of _items | filter:{label: filterText}">{{ item.label }}</li>
</ul>

https://long2know.com/2016/11/angular2-filter-pipes/

答案 20 :(得分:0)

我知道这是一个老问题,但是,我认为提供另一个解决方案可能会有所帮助。

与此AngularJS等效

<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>

在Angular 2+中,您不能在同一元素上使用* ngFor和* ngIf,因此它将如下:

<div *ngFor="let item of itemsList">
     <div *ngIf="conditon(item)">
     </div>
</div>

,如果您不能用作内部容器,请使用ng-container代替。 当您想在应用程序中有条件地附加一组元素(即使用* ngIf =“ foo”),但又不想用其他元素包装它们时,ng-container很有用。

答案 21 :(得分:0)

我在寻找某种东西来制作通过对象的过滤器,然后可以像多重过滤器一样使用它:Multi filter example

我做了这个美容方案:

filter.pipe.ts

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

@Pipe({
  name: 'filterx',
  pure: false
})
export class FilterPipe implements PipeTransform {
 transform(items: any, filter: any, isAnd: boolean): any {
  let filterx=JSON.parse(JSON.stringify(filter));
  for (var prop in filterx) {
    if (Object.prototype.hasOwnProperty.call(filterx, prop)) {
       if(filterx[prop]=='')
       {
         delete filterx[prop];
       }
    }
 }
if (!items || !filterx) {
  return items;
}

return items.filter(function(obj) {
  return Object.keys(filterx).every(function(c) {
    return obj[c].toLowerCase().indexOf(filterx[c].toLowerCase()) !== -1
  });
  });
  }
}

component.ts

slotFilter:any={start:'',practitionerCodeDisplay:'',practitionerName:''};

componet.html

             <tr>
                <th class="text-center">  <input type="text" [(ngModel)]="slotFilter.start"></th>
                <th class="text-center"><input type="text" [(ngModel)]="slotFilter.practitionerCodeDisplay"></th>
                <th class="text-left"><input type="text" [(ngModel)]="slotFilter.practitionerName"></th>
                <th></th>
              </tr>


 <tbody *ngFor="let item of practionerRoleList | filterx: slotFilter">...

答案 22 :(得分:0)

我使用了一个动态过滤器管道

源数据:

items = [{foo: 'hello world'}, {foo: 'lorem ipsum'}, {foo: 'foo bar'}];

在模板中,您可以在任何对象属性中动态设置过滤器:

<li *ngFor="let item of items | filter:{foo:'bar'}">

管道:

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

  @Pipe({
    name: 'filter',
  })
  export class FilterPipe implements PipeTransform {
    transform(items: any[], filter: Record<string, any>): any {
      if (!items || !filter) {
        return items;
      }

      const key = Object.keys(filter)[0];
      const value = filter[key];

      return items.filter((e) => e[key].indexOf(value) !== -1);
    }
  }

不要忘记在您的app.module.ts声明中注册管道