显然,Angular 2将使用管道代替Angular1中的ng-for过滤器来过滤结果,尽管实现起来似乎还很模糊,没有明确的文档。
即我可以从以下角度看待我要实现的目标
<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>
如何使用管道来实现?
*ngFor
和*ngIf
在同一元素上。您需要为其中之一更改为显式形式”
显然,Angular 2将使用管道代替Angular1中的ng-for过滤器来过滤结果,尽管实现起来似乎还很模糊,没有明确的文档。
即我可以从以下角度看待我要实现的目标
<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>
如何使用管道来实现?
*ngFor
和*ngIf
在同一元素上。您需要为其中之一更改为显式形式”
Answers:
基本上,您编写了一个管道,然后可以在*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 { }
这是一个Plunker,它演示了如何使用自定义过滤器管道和内置切片管道来限制结果。
请注意(正如一些评论家所指出的那样),Angular中没有内置过滤器管道是有原因的。
*ngFor
参数包装在括号中,以避免任何混淆并使它“防更改”:<li *ngFor="let item of (items | myfilter:filterargs)">
你们中的许多人都有很好的方法,但是这里的目标是通用并定义一个数组管道,该数组管道在与* 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));
}
}
然后,在您的组件中,您需要实现一个具有以下签名的方法(项目: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在需要通过回调过滤的所有数组(如项)中是相当通用的。在mycase中,我发现它对于* 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>
如果将变量用作第二个参数,请不要使用引号。
这是我在不使用管道的情况下实现的。
<div *ngFor="let item of filter(itemsList)">
@Component({
....
})
export class YourComponent {
filter(itemList: yourItemType[]): yourItemType[] {
let result: yourItemType[] = [];
//your filter logic here
...
...
return result;
}
}
itemList
成为Observable并使用异步过滤器:let item of itemsList | async
。发生更改时,使可观察对象发出新列表。这样,过滤代码仅在需要时运行。
我不确定它什么时候进来的,但是他们已经制造了可以做到这一点的切片管。它也有据可查。
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"
您还可以使用以下内容:
<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>
Angular2中的管道类似于命令行上的管道。每个先前值的输出在管道之后被馈送到过滤器中,这使得链接过滤器变得容易,如下所示:
<template *ngFor="#item of itemsList">
<div *ngIf="conditon(item)">{item | filter1 | filter2}</div>
</template>
item
从*ng-for="#item of itemsList"
应该使用来过滤结果*ng-if="conditon(item)"
。这确实在这个例子不会工作。
item
如果满足条件,条件将只返回,否则将不返回任何值。
*ngFor
和*ngIf
不支持在同一元素上。你需要改变,以明确的形式,其中之一<template ngFor ...>
为此,我实现并发布了通用组件。看到
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"
,它正在我的列表中搜索,但显示空白列表,您知道为什么吗?
与Angular 6一起使用的用于过滤ngFor的简单解决方案如下:
<span *ngFor="item of itemsList" >
<div *ngIf="yourCondition(item)">
your code
</div>
</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>
我喜欢用于特定于应用程序的筛选器的另一种方法是在组件上使用自定义的只读属性,与使用自定义管道(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>
我发现对于特定于应用程序的专用过滤器,它比管道更有效,因为它保持与组件过滤器相关的逻辑。
管道对于全局可重用的过滤器效果更好。
我创建了以下管道,用于从列表中获取所需的项目。
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>
基于上面提出的非常优雅的回调管道解决方案,可以通过允许传递其他过滤器参数来对其进一步概括。然后我们有:
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>
这是我创建一段时间并在博客上发布的示例,其中包含一个正在工作的插件。它提供了可以过滤任何对象列表的过滤器管道。基本上,您只需在ngFor规范中指定属性和值{key:value}。
它与@NateMay的响应没有太大不同,只是我以相对冗长的细节进行了解释。
就我而言,我使用这种标记过滤了用户输入的一些文本(filterText)的无序列表,该文本是针对我数组中对象的“ label”属性的:
<ul>
<li *ngFor="let item of _items | filter:{label: filterText}">{{ item.label }}</li>
</ul>
您使用创建过滤器的第一步 @Pipe
在component.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对象的数据结构:
人
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>
这是你的数组
products: any = [
{
"name": "John-Cena",
},
{
"name": "Brock-Lensar",
}
];
这是您的ngFor循环Filter By:
<input type="text" [(ngModel)]='filterText' />
<ul *ngFor='let product of filterProduct'>
<li>{{product.name }}</li>
</ul>
在那里,我使用产品的filterProduct Instant,因为我想保留原始数据。这里的_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);
}
我正在寻找使通过对象的过滤器的方法,然后可以像多重过滤器一样使用它:
我做了这个美容解决方案:
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">...
<div *ngFor="let item of itemsList" *ngIf="conditon(item)" ...