首页 文章

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

提问于
浏览
191

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

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

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

如何使用管道实现?

21 回答

  • 4

    基本上,您编写一个管道,然后可以在 *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中没有内置的过滤管道 .

  • 65

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

    callback.pipe.ts (don 't forget to add this to your module' s声明数组)

    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) => boolean ,在我的例子中,我称之为filterUser,它过滤用户的年龄超过18年 .

    Your Component

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

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

    Your HTML

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

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

    希望这可以帮助!!!

    codematrix

  • 1

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

    见:https://angular.io/docs/ts/latest/guide/pipes.html#!#no-filter-pipe

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

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

  • 0

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

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

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

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

    您还可以使用以下内容:

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

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

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

    对于此要求, I implement and publish a generic component . 看到

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

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

    npm install w-ng5 --save
    

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

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

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

    imports: [
      PipesModule,
      ...
    ]
    

    Sample use

    Filtering simple string

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

    Filtering complex string - field 'Value' in level 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>
    

    Filtering complex string - middle field - 'Value' in level 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>
    

    Filtering complex array simple - field 'Nome' level 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>
    

    Filtering in tree fields - field 'Valor' in level 2 or 'Valor' in level 1 or 'Nome' in level 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>
    

    Filtering nonexistent field - 'Valor' in nonexistent level 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>
    

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

  • 7

    我根据这里和其他地方的答案创建了一个plunker .

    另外,我必须添加一个 @Input@ViewChildElementRef<input> 并创建和 subscribe() 到它的一个observable .

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

  • 294

    管道是最好的方法 . 但是低于一个也会有效 .

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

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

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

    管道更适合全局可重用的过滤器 .

  • 0

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

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

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

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

    这是我的代码:

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

    这是我在一段时间后创建的一个例子,其中包括一个有效的插件 . 它提供了一个过滤管道,可以过滤任何对象列表 . 您基本上只需在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/

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

    component

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

    在component.ts文件中使用 @Pipe 创建Filter的第一步:

    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>
    
  • 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);
            }
    
  • 23

    经过一些谷歌搜索,我遇到了 ng2-search-filter . In将获取您的对象并对所有寻找匹配项的对象属性应用搜索项 .

  • 1

    一个简单的解决方案,与Angular 6一起用于过滤ngFor,它是以下内容:

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

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

  • 6

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

    相当于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非常有用 .

相关问题