显然,Angular 2将使用管道代替Angular1中的ng-for来过滤结果,尽管实现起来似乎还很模糊,并且没有明确的文档。可以从以下角度查看尝试实现的目标

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


如何使用管道来实现?

评论

请注意,针对哈希符号的ngFor在beta 17中引入了重大更改。正确的方法是:

angulartutorial.net/2016/06/…

来自Gunter的@MemetOlsen评论如下:“不支持同一元素上的* ngFor和* ngIf。您需要更改其中一个的显式形式”

即使这是OP的要求,也建议不要在Angular2 +中使用PIPE进行过滤或排序。最好具有带有过滤值的class属性:angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

#1 楼

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

在组件中:



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


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

< pre class =“ lang-none prettyprint-override”> <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中。

评论


谢谢,这是按预期工作的,但是有时最好检查是否定义了items数组而不是null,因为Ng2可能会尝试在“ items”仍未定义的情况下应用过滤器。

–timmz
16 Mar 17 '16 at 16:50

另外,我需要将过滤器类添加到@Component声明中。像这样:@Component({...管道:[MyFilterPipe]

–斯蒂芬
16年7月11日在18:01



我认为在数组为空的情况下,它也需要此行“ f(!items)返回项目”。

–BoštjanPišler
16年12月21日在16:02

Angular表示使用Pipe存在性能问题,因此建议对组件进行过滤

–塞巴斯蒂安·罗哈斯(SebastiánRojas)
17年7月17日在19:31



我想建议将* ngFor参数包装在括号中,以避免任何混淆并使它“防更改”:

– Tomas
18年5月25日在10:36



#2 楼

你们中的许多人都有很好的方法,但是这里的目标是通用并定义一个数组管道,该数组管道与* 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在所有数组(如需要通过回调过滤的项)中都是通用的。就我而言,我发现它对于* ngFor类似场景非常有用。

希望对您有所帮助!

codematrix

评论


我注意到在函数filterUser()或与之等效的函数中,您无法像使用组件类中的所有其他函数一样使用“ this”来访问当前组件实例。我需要访问组件对象以检查过滤后的项在集合中。

– Paul
17年11月16日在15:56

@Paul,嗯...那是不可能的。您的方法私密吗?没关系,因为private只是编译结构,不会在运行时强制执行。在我的示例中,我使用了IUser。这假定要迭代的集合中的项目映射到它。您可以尝试任何一种,看看是否可行。另外,请确保输入正确的名称,大小写和全部。

–code5
17年11月18日在3:54

我无法使用此方法访问组件变量

– suulisin
18年1月15日在16:52

为避免此问题未定义,您可以在您的组件上编写方法,例如filterUser =(user:IUser)=>而不是filteruser(user:IUser)

–汤姆
19年1月18日在16:41

@Paul我知道这对您有所帮助为时已晚,但它可能会对其他人有所帮助。之所以在组件方法上丢失它,是因为该方法被用作回调并应用了新的this上下文。您在面向对象的javascript中遇到了一个常见问题,但是有一个古老而又简单的解决方案:将要用作回调的方法绑定到原始类。在构造函数中,添加以下代码:this.myCallbackFunc = this.myCallbackFunc.bind(this);而已。您将再也不会失去它。

–兰多福
19年12月16日在16:32

#3 楼

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

请参阅: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>


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

评论


也许添加以下内容以显示如何将其与ReqExp组合:return items.filter(item => {return new RegExp(value,“ i”)。test(item [field])});

–约翰内斯
16 Jun 30'15:25



根据Angular团队的说法,这被认为是不好的做法。

–user663031
17 Mar 15 '17 2:33

@torazaburo您可以参考他们的意见或解释原因吗?谢谢

–Zymotik
17年5月15日在22:32

@Zymotik参见angular.io/docs/ts/latest/guide/…。

–user663031
17年5月16日在3:27

根据Angular团队的说法,这是糟糕的代码,因为它运行缓慢且无法很好地缩小。该团队不希望由于其代码而看到缓慢的网站,因此这次他们没有将其构建到Angular中。 angular.io/docs/ts/latest/guide / ...

–Zymotik
17年5月23日在8:44

#4 楼

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

component.html

br />

评论


我认为这会占用大量计算资源,因为Angular每次运行更改检测都会执行过滤器。它不能很好地扩展到大型阵列。较干净的代码(尽管对代码更复杂)解决方案是使itemList成为Observable并使用异步过滤器:异步。发生更改时,使可观察对象发出新列表。这样,过滤代码仅在需要时运行。

– BeetleJuice
17-09-25在11:06

该答案应为负分。不好,用管子。

–Cétia
2月14日15:54

我不确定我是否理解这很糟糕的原因,无论您使用什么,在更改检测期间管道或其他任何东西都不一定会被过滤掉吗?如果在管道中放置一个断点,您将看到它在每次更改检测时仍在运行。可观察的方法比trackBy有什么更好的方法,因为到最后还是需要根据值进行过滤可能会改变的变量的..?您可以使用单独的列表进行更新,然后再推送更改。

–丹·蔡斯(Dan Chase)
8月17日在16:05



#5 楼

我不确定它什么时候进来的,但是他们已经制作了可以做到这一点的切片管。

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>


评论


如果使用trackBy接口,则必须在;之前应用切片管道。例如:* ngFor =“让内容具有功能吗?.keyFeatures | slice:1:5; trackBy功能?.id”

–菲利普
16年11月28日在12:50



#6 楼

您还可以使用以下命令:

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


评论


这不是输入列表中每个项目的模板,而不是输入过滤后的列表吗?这可能会影响性能。

– Azeroth2b
18年7月6日在14:38

#7 楼

Angular2中的管道类似于命令行中的管道。每个先前值的输出都在管道之后输入到过滤器中,这使得过滤器的链接也很容易,如下所示:

评论


抱歉,如果这令人误解,我的意思是* ng-for =“ itemsList的#item”中的变量item应该用于过滤结果,例如* ng-if =“ conditon(item)”。在此示例中不起作用。

–卡乐德
2015年12月8日在19:40



您可以将条件设​​为过滤器,并使用{{item | condition}}条件将仅返回满足条件的项目,否则将不返回任何值。

–本·格拉瑟(Ben Glasser)
15年12月8日在19:43

@BenGlasser我认为管道是从右到左应用的。因此,这将首先应用filter2,然后再应用filter1。

–伊文·普莱斯
16年1月25日在18:58

不支持同一元素上的* ngFor和* ngIf。您需要更改其中之一的显式形式