如何应用过滤器*ngFor?

显然,Angular 2将像在Angular1中一样使用管道而不是过滤器,并结合ng-for来过滤结果,尽管实现看起来仍然很模糊,没有明确的文档。

也就是说,我想要达到的目标可以从以下角度来看待

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

如何实现这样使用管道?

527642 次浏览

Angular2中的管道类似于命令行中的管道。前面每个值的输出在管道之后被送入过滤器,这使得链过滤器很容易,就像这样:

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

基本上,你写了一个管道,然后在*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 { }

这是普伦克,它演示了使用自定义过滤管道和内置切片管道来限制结果。

请注意(正如一些评论员指出的那样)这是有原因的为什么Angular中没有内置的过滤管道。

你也可以使用以下语句:

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

这将只显示div,如果您的项目符合条件

参见角的文档获取更多信息 如果您还需要索引,请使用以下命令:

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

简化方式(由于性能问题,仅用于小型数组。在大型数组中,你必须通过代码手动创建过滤器):

看: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>

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

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

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>

我喜欢用于特定于应用程序的过滤器的另一种方法是在组件上使用自定义只读属性,这允许您比使用自定义管道(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>

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

管道对于全局可重用过滤器工作得更好。

我根据这里和其他地方的答案创建了一个活塞。

此外,我必须添加<input>@Input@ViewChildElementRef,并创建和subscribe()到它的一个可观察对象。

Angular2搜索过滤器:PLUNKR(更新:plunker不再工作)

这是我不久前创建的一个例子,并在博客上发表过,其中包括一个工作的扑通。它提供了一个过滤管道,可以过滤任何对象列表。基本上你只需要在ngFor规范中指定属性和值{key:value}。

这与@NateMay的回复没有太大不同,只是我比较详细地解释了它。

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

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

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

很多人都有很好的方法,但这里的目标是通用的和定义的数组管道,它在与*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) =>布尔值的方法,在我的例子中,我称之为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>

正如您所看到的,这个Pipe对于所有需要通过回调筛选的数组(如项目)都是相当通用的。在我的情况下,我发现它是非常有用的*ngFor类似的场景。

希望这能有所帮助!!

codematrix

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

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

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

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>

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

<ng-container *ngFor="item in itemsList">
<div*ngIf="conditon(item)">\{\{item}}</div>
</ng-container>

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

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.>;
}

超文本标记语言

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

第一步在组件中使用@Pipe创建Filter。ts文件:

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>

管子是最好的方法。但低于1也可以。

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

这是你的数组

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


}
];
这是你的ngFor循环 过滤By:

<input type="text" [(ngModel)]='filterText' />
<ul *ngFor='let product of filterProduct'>
<li>\{\{product.name }}</li>
</ul>
这里我使用的是产品的filterProduct instant,因为我想保留我的原始数据。 这里model _filterText用作输入框。当有任何变化setter函数将调用。 在setFilterText调用performProduct时,它只返回与输入匹配的结果。我用小写表示不区分大小写。< / p >
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);
}

对于这个需求,我实现并发布了一个通用组件。看到

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

在使用此组件之前,使用npm安装此包:

npm install w-ng5 --save

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

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

下一步,在app.module中添加declare部分:

imports: [
PipesModule,
...
]

样本用

过滤简单字符串

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

在级别2中过滤复杂字符串字段“Value”

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

过滤复杂字符串-中间字段- 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>

过滤复杂数组的简单字段“Nome”级别为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>

在树字段中过滤-在第2级中字段'Valor'或在第1级中字段'Valor'或在第0级中字段'Nome'

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

过滤不存在的字段- 'Valor'在不存在的级别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>

该组件具有无限属性级别…

在谷歌了一下之后,我发现了ng2-search-filter。In将获取您的对象并对所有对象属性应用搜索项以查找匹配项。

在Angular 6中过滤ngFor的一个简单解决方案如下:

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

your code
    

</div>
</span>

span很有用,因为它本身并不代表任何东西。

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

相当于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是有用的

这是我的代码:

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>

我正在寻找使过滤器传递对象的东西,然后我可以像multi-filter: 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">...

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

源数据:

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

在模板中,你可以在任意对象attr中动态设置过滤器:

<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声明中注册管道

下面给出了限制ngFor的最简单易行的方法

<li *ngFor="let item of list | slice:0:10; let i=index" class="dropdown-item" >\{\{item.text}}</li>

你可以这样做:

<ng-container *ngFor="item in items">
<div *ngIf="conditon(item)">\{\{ item.value }}</div>
</ng-container>

<div *ngFor="item in items">
<ng-container *ngIf="conditon(item)">\{\{ item.value }}</ng-container>
</div>