web-dev-qa-db-ja.com

* ngForにフィルタを適用するにはどうすればいいですか?

明らかに、Angular 2はng-forと組み合わせてAngular 1のようにフィルタの代わりにパイプを使用して結果をフィルタリングしますが、実装はまだ曖昧なようで、明確なドキュメントはありません。

つまり、私が達成しようとしていることは、次の観点から見ることができます。

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

パイプを使ってそのように実装するには?

199
Khaled

基本的に、*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に組み込みのフィルターパイプがない理由.

301
phuc77

多くの人が素晴らしいアプローチを持っていますが、ここでの目標は* 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)=> boolean でメソッドを実装する必要があります。 。

あなたのコンポーネント

@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

67
code5

単純化された方法(パフォーマンス上の問題から、小さな配列でのみ使用されます。大きな配列では、コードを使用して手動でフィルタを作成する必要があります)。

参照してください: 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>

2番目の引数として変数を使用する場合は、引用符を使用しないでください。

これは私がpipeを使わずに実装したものです。

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;
  }
}
24
Thang Le

いつそれが入ってきたのか私にはわかりませんが、彼らはすでにそれを行うスライスパイプを作りました。それもよく文書化されています。

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

次のものも使用できます。

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

これはあなたのアイテムが条件にマッチする場合にのみdivを表示します

詳細については Angularのドキュメント を参照してください。インデックスも必要な場合は、以下を使用してください。

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

angular 2のパイプは、コマンドラインのパイプに似ています。各先行値の出力はパイプの後のフィルタに供給されます。

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

この要求に対して、 一般的なコンポーネントを実装して公開します 。見る

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の 'Value'

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

このコンポーネントは無限の属性レベルで動作します...

私はここと他の場所で答えに基づいてプランカーを作成しました。

さらに、私は@Input@ViewChild<input>、およびElementRefを追加し、それを観察するためにcreateおよびsubscribe()を追加する必要がありました。

Angular 2検索フィルター: _ plunkr _ (更新日:plunkerはもはや動作しません)

4
Nate May

パイプが最善の方法です。しかし、以下のものでもうまくいくでしょう。

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

私がアプリケーション固有のフィルタに使用したいもう1つのアプローチは、カスタムパイプ(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>

私は、特定のアプリケーションに特化した特殊なフィルタを見つけることができます。これは、コンポーネントに関連したフィルタに関連するロジックを保持するため、パイプよりもうまく機能します。

パイプは、世界規模で再利用可能なフィルタに適しています。

1
Rick Strahl

理想的には、角度2のパイプを作成する必要があります。しかし、あなたはこのトリックを行うことができます。

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

NgForをフィルタリングするためのAngular 6と連携する簡単な解決策は、次のとおりです。

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

スパンは本質的に何も表していないので便利です。

1
Michael V

これは私のコードです:

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
Pàldi Gergő

リストから希望の項目を取得するために、次のパイプを作成しました。

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>
1
Sanchit Tandon

あなたのcomponent.tsファイルの@Pipeを使ってフィルタを作成する最初のステップ:

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

私はその古い質問を知っています、しかし、私はそれが別の解決策を提供することが役に立つかもしれないと思いました。

これの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"を使用したい)がそれらを別の要素でラップしたくない場合に便利です。

0
tgralex

グーグルの後、私はng2-search-filterに出会いました。 Inはあなたのオブジェクトを受け取り、一致を探しているすべてのオブジェクトプロパティに対して検索語を適用します。

0
alindber

これは私がしばらく前に作成してブログを書いた例です。これは、オブジェクトのリストをフィルタリングできるフィルタパイプを提供します。基本的には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
long2know

これはあなたの配列です

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);
        }
0
Gajender Singh

上で提案された非常に洗練されたコールバックパイプソリューションに基づいて、追加のフィルタパラメータが渡されるのを許容することによってそれをもう少し一般化することは可能です。それから、

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