显然,Angular 2 将使用管道而不是 Angular1 中的过滤器,并结合 ng-for 来过滤结果,尽管实现似乎仍然模糊,没有明确的文档。
即可以从以下角度看待我想要实现的目标
<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>
如何使用管道来实现?
<div *ngFor="let item of itemsList" *ngIf="conditon(item)" ...
*ngFor
和 *ngIf
。您需要将其中一个更改为显式形式”
基本上,您编写一个管道,然后您可以在 *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 中没有内置过滤器管道。
你们中的很多人都有很好的方法,但这里的目标是通用并定义一个数组管道,它在与 *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));
}
}
然后在您的组件中,您需要实现一个具有以下签名(项目:任何)=> 布尔值的方法,例如,在我的例子中,我称之为 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>
如您所见,此管道在所有数组中都相当通用,例如需要通过回调过滤的项目。在我的情况下,我发现它对于 *ngFor 之类的场景非常有用。
希望这可以帮助!!!
代码矩阵
this
未定义的问题,您可以在组件上编写方法,例如 filterUser = (user: IUser) =>
而不是 filteruser(user: IUser)
this
的原因是该方法被用作回调并且应用了新的 this
上下文。您在面向对象的 javascript 中遇到了一个常见问题,但有一个古老而简单的解决方案:您绑定方法以用作原始类的回调。在您的构造函数中,添加以下代码: this.myCallbackFunc = this.myCallbackFunc.bind(this);
就是这样。您永远不会再失去 this
。
简化方式(由于性能问题仅用于小型阵列。在大型阵列中,您必须通过代码手动制作过滤器):
请参阅: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>
如果您使用变量作为第二个参数,请不要使用引号。
这是我在不使用管道的情况下实现的。
组件.html
<div *ngFor="let item of filter(itemsList)">
组件.ts
@Component({
....
})
export class YourComponent {
filter(itemList: yourItemType[]): yourItemType[] {
let result: yourItemType[] = [];
//your filter logic here
...
...
return result;
}
}
itemList
设为 Observable 并使用异步过滤器:let item of itemsList | async
。当发生变化时,让 observable 发出新的列表。这样,过滤代码仅在需要时运行。
我不确定它什么时候进来的,但他们已经制作了可以做到这一点的切片管。它也有据可查。
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>
;
之前应用切片管道。例如:*ngFor="let feature of content?.keyFeatures | slice:1:5; trackBy feature?.id"
一个与 Angular 6 一起用于过滤 ngFor 的简单解决方案,如下所示:
跨度很有用,因为它本身并不代表任何东西。
您还可以使用以下内容:
<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>
Angular2 中的管道类似于命令行中的管道。每个先前值的输出在管道之后被馈送到过滤器,这使得链接过滤器很容易,如下所示:
<template *ngFor="#item of itemsList">
<div *ngIf="conditon(item)">{item | filter1 | filter2}</div>
</template>
*ng-for="#item of itemsList"
中的变量 item
应该用于过滤结果,例如 *ng-if="conditon(item)"
。这在这个例子中不起作用..
item
,否则不返回值。
*ngFor
和 *ngIf
。您需要更改其中之一的显式形式 <template ngFor ...>
我知道这是一个老问题,但是,我认为提供另一种解决方案可能会有所帮助。
相当于这个的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。 ng-container 在您想有条件地在应用程序中附加一组元素(即使用 *ngIf="foo")但又不想用另一个元素包装它们时很有用。
我使用了一个动态过滤器管道
源数据:
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
声明中注册管道
针对这个需求,我实现并发布了一个通用组件。看
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>
过滤复杂字符串 - 级别 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>
过滤复杂字符串 - 中间字段 - 级别 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>
过滤不存在的字段 - 不存在级别 3 中的“Valor”
<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>
该组件适用于无限属性级别...
*ngFor="let inovice of invoices | filter:searchInvoice"
,它正在我的列表中搜索,但显示一个空白列表,你知道为什么吗?
管道将是最好的方法。但低于一个也可以。
<div *ng-for="#item of itemsList">
<ng-container *ng-if="conditon(item)">
// my code
</ng-container>
</div>
我根据这里和其他地方的答案创建了一个 plunker。
此外,我必须添加 <input>
的 @Input
、@ViewChild
和 ElementRef
,并将 subscribe()
创建到它的 observable。
Angular2 搜索过滤器:PLUNKR(更新:plunker 不再工作)
基于上面提出的非常优雅的回调管道解决方案,可以通过允许传递额外的过滤器参数来进一步概括它。然后我们有:
回调.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>
这是我的代码:
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>
我喜欢用于特定于应用程序的过滤器的另一种方法是在组件上使用自定义只读属性,它允许您比使用自定义管道(恕我直言)更干净地封装过滤逻辑。
例如,如果我想绑定到 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>
我发现对于特定于应用程序的专用过滤器,这比管道更有效,因为它将与过滤器相关的逻辑与组件保持在一起。
管道更适合全局可重复使用的过滤器。
我创建了以下管道以从列表中获取所需的项目。
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>
这是我不久前创建的一个示例,并在博客中提到,其中包括一个有效的 plunk。它提供了一个过滤管道,可以过滤任何对象列表。您基本上只需在 ngFor 规范中指定属性和值 {key:value} 。
这与@NateMay 的回复并没有太大的不同,只是我用相对冗长的细节进行了解释。
在我的例子中,我使用这种标记过滤了用户针对我数组中对象的“标签”属性输入的一些文本(filterText)的无序列表:
<ul>
<li *ngFor="let item of _items | filter:{label: filterText}">{{ item.label }}</li>
</ul>
https://long2know.com/2016/11/angular2-filter-pipes/
在您的 component.ts 文件中使用 @Pipe
创建过滤器的第一步:
你的.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对象的数据结构:
个人.ts
export class Person{
constructor(
public firstName: string,
public lastName: string
) { }
}
在您的 html 文件视图中:
你的.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>
这是你的数组
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 用作输入框。每当有任何更改设置器函数都会调用。在 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);
}
经过一番谷歌搜索,我发现了 ng2-search-filter
。 In 将获取您的对象并将搜索词应用于所有对象属性以寻找匹配项。
https://i.stack.imgur.com/VnazQ.png
我做了这个美容解决方案:
过滤器.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
});
});
}
}
组件.ts
slotFilter:any={start:'',practitionerCodeDisplay:'',practitionerName:''};
组件.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">...
下面给出了限制您的 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>
*ngFor
参数括在括号中,以避免任何混淆并使其“防更改”:<li *ngFor="let item of (items | myfilter:filterargs)">