วิธีการใช้ตัวกรองกับ * ngFor


278

เห็นได้ชัดว่า Angular 2 จะใช้ท่อแทนตัวกรองเช่นเดียวกับใน Angular1 ร่วมกับ ng-for เพื่อกรองผลลัพธ์แม้ว่าการดำเนินการยังคงคลุมเครือโดยไม่มีเอกสารที่ชัดเจน

คือสิ่งที่ฉันพยายามบรรลุผลสามารถดูได้จากมุมมองต่อไปนี้

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

วิธีการใช้งานโดยใช้ท่อ?


8
โปรดทราบว่ามีการเปิดตัวการเปลี่ยนแปลงที่ไม่สิ้นสุดในเบต้า 17 สำหรับ ngFor เกี่ยวกับสัญลักษณ์แฮช วิธีที่ถูกต้องคือ:<div *ngFor="let item of itemsList" *ngIf="conditon(item)" ...
Memet Olsen


11
@MemetOlsen ความคิดเห็นจาก Gunter ด้านล่าง: " *ngForและ*ngIfในองค์ประกอบเดียวกันไม่ได้รับการสนับสนุนคุณต้องเปลี่ยนเป็นรูปแบบที่ชัดเจนสำหรับหนึ่งในนั้น"
The Red Pea

1
แม้จะเป็นสิ่งที่ OP ต้องการ แต่ก็ไม่แนะนำให้ใช้ท่อสำหรับกรองหรือสั่งซื้อใน Angular2 + ต้องการคุณสมบัติคลาสที่มีค่าตัวกรอง: angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe
ylerjen

คำตอบ:


395

โดยทั่วไปคุณเขียนไพพ์ซึ่งคุณสามารถใช้ใน*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ซึ่งสาธิตการใช้ไพพ์ฟิลเตอร์แบบกำหนดเองและไพลิสบิวด์ในตัวเพื่อ จำกัด ผลลัพธ์

โปรดทราบว่า (เนื่องจากมีผู้แสดงความคิดเห็นหลายคนชี้ให้เห็น) ว่ามีเหตุผลที่ไม่มีท่อฟิลเตอร์ในตัวในแองกูลาร์


6
ก่อนหน้านี้ใช้งานได้ตามปกติ แต่บางครั้งก็เป็นการดีกว่าที่จะตรวจสอบว่ามีการกำหนดอาร์เรย์รายการและไม่เป็นโมฆะหรือไม่เนื่องจาก Ng2 อาจลองใช้ตัวกรองในขณะที่ "รายการ" ยังไม่ได้กำหนด
timmz

1
นอกจากนี้ฉันต้องการเพิ่มคลาสตัวกรองลงในการประกาศ @Component เช่นเดียวกับ: @Component ({... pipes: [MyFilterPipe]
Stephen

1
ฉันคิดว่ามันต้องใช้บรรทัดนี้ìf (! items) ส่งคืนไอเท็ม `ในกรณีที่อาร์เรย์ว่างเปล่า
BoštjanPišler

2
Angular กล่าวว่าการใช้ Pipe มีปัญหาในการทำงานดังนั้นแนะนำให้ทำการกรองส่วนประกอบ
Sebastián Rojas

3
ฉันอยากจะแนะนำให้ห่อ*ngForพารามิเตอร์ในวงเล็บเพื่อหลีกเลี่ยงความสับสนและทำให้ "พิสูจน์การเปลี่ยนแปลง":<li *ngFor="let item of (items | myfilter:filterargs)">
Tomas

104

พวกคุณหลายคนมีวิธีการที่ยอดเยี่ยม แต่เป้าหมายที่นี่คือการเป็นแบบทั่วไปและกำหนดไปป์อาเรย์ที่สามารถนำมาใช้ซ้ำได้อย่างมากในทุกกรณีที่สัมพันธ์กับ * 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>

อย่างที่คุณเห็นท่อนี้ค่อนข้างทั่วไปในอาร์เรย์ทั้งหมดเช่นรายการที่ต้องกรองผ่านการเรียกกลับ ใน mycase ฉันพบว่ามันมีประโยชน์มากสำหรับ * ngFor เช่นสถานการณ์

หวังว่านี่จะช่วย !!!

codematrix


4
ฉันสังเกตเห็นว่าใน function filterUser () - หรือฟังก์ชั่นที่เทียบเท่ากับของคุณ - คุณไม่สามารถใช้ "this" เพื่อเข้าถึงอินสแตนซ์ขององค์ประกอบปัจจุบันอย่างที่คุณสามารถทำได้กับฟังก์ชั่นอื่น ๆ ทั้งหมดในคลาสคอมโพเนนต์ ฉันจำเป็นต้องเข้าถึงวัตถุองค์ประกอบเพื่อตรวจสอบรายการที่กรองอยู่ในคอลเลกชัน
พอล

1
@ พอลอืม ... มันเป็นไปไม่ได้ วิธีการของคุณเป็นส่วนตัวหรือไม่? ไม่ใช่ว่าควรมีความสำคัญเนื่องจากไพร่พลเป็นเพียงการรวบรวมการสร้างและไม่ได้บังคับใช้ในขณะทำงาน ในตัวอย่างของฉันฉันใช้ IUser นี่ถือว่ารายการในคอลเลกชันที่มีการทำซ้ำแผนที่กับมัน คุณสามารถลองใด ๆ เพื่อดูว่ามันทำงาน ตรวจสอบให้แน่ใจว่าพิมพ์ชื่อถูกต้องตัวพิมพ์ใหญ่และตัวพิมพ์ทั้งหมด
code5

1
ฉันลาดเทเข้าถึงตัวแปรองค์ประกอบที่ใช้วิธีนี้
suulisin

10
เพื่อหลีกเลี่ยงปัญหาของthisถูกไม่ได้กำหนดคุณสามารถเขียนวิธีการของคุณในส่วนของคุณชอบfilterUser = (user: IUser) =>มากกว่าfilteruser(user: IUser)
ทอม

2
@ พอลฉันรู้ว่ามันสายเกินไปที่จะช่วยคุณ แต่อาจช่วยคนอื่นได้ เหตุผลที่คุณสูญเสียthisวิธีการส่วนประกอบของคุณเป็นเพราะวิธีการที่ถูกใช้เป็นโทรกลับและthisบริบทใหม่ถูกนำไปใช้ คุณพบปัญหาทั่วไปในจาวาสคริปต์แบบเชิงวัตถุ แต่มีวิธีแก้ปัญหาแบบเก่าและง่าย: คุณผูกวิธีที่จะใช้เป็นการเรียกกลับไปที่คลาสเดิม ในตัวสร้างของคุณเพิ่มรหัสต่อไปนี้: แค่this.myCallbackFunc = this.myCallbackFunc.bind(this); นี้แหละ คุณจะไม่สูญเสียthisอีกครั้ง
Randolpho

36

วิธีที่ง่ายกว่า (ใช้ในอาร์เรย์ขนาดเล็กเท่านั้นเนื่องจากปัญหาด้านประสิทธิภาพในอาร์เรย์ขนาดใหญ่คุณต้องสร้างตัวกรองด้วยตนเองผ่านรหัส):

ดู: 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>

หากคุณใช้ตัวแปรเป็นอาร์กิวเมนต์ที่สองอย่าใช้เครื่องหมายคำพูด


3
อาจเพิ่มต่อไปนี้เพื่อแสดงวิธีรวมกับ ReqExp: return items.filter (item => {return RegExp ใหม่ (ค่า, "i"). test (รายการ [field])});
โยฮันเนส

8
ตามที่ทีมงานเชิงมุมนี้ถือว่าเป็นการปฏิบัติที่ไม่ดี

@torazaburo คุณสามารถอ้างอิงความคิดเห็นของพวกเขาหรืออธิบายว่าทำไม ขอบคุณ
Zymotik

1
@Zymotik ดูangular.io/docs/ts/latest/guide/...

2
ตามรายงานของทีม Angular นี่เป็นรหัสที่แย่เพราะมันช้าและมันไม่ได้ลดขนาดลง ทีมไม่ต้องการเห็นเว็บไซต์ที่ช้าเนื่องจากรหัสของพวกเขาดังนั้นพวกเขาจึงไม่ได้สร้างไว้ใน Angular ในเวลานี้ angular.io/docs/ts/latest/guide/…
Zymotik

29

นี่คือสิ่งที่ฉันนำไปใช้โดยไม่ต้องใช้ไพพ์

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

16
ฉันคิดว่าสิ่งนี้จะต้องใช้การคำนวณอย่างเข้มข้นเพราะ Angular จะดำเนินการตัวกรองทุกครั้งที่ตรวจพบการเปลี่ยนแปลง มันจะไม่ปรับขนาดได้ดีกับอาร์เรย์ขนาดใหญ่ ทำความสะอาด แต่ที่ซับซ้อนมากขึ้นการให้รหัสการแก้ปัญหาจะทำให้itemListสังเกตและใช้ตัวกรอง async let item of itemsList | asyncนี้: เมื่อมีการเปลี่ยนแปลงเกิดขึ้นให้ผู้สังเกตการณ์ปล่อยรายการใหม่ วิธีนี้รหัสการกรองจะทำงานเมื่อจำเป็นเท่านั้น
BeetleJuice

1
คำตอบนี้ควรจะมีคะแนนลบ ไม่ดีใช้ท่อ
เซเตีย

19

ฉันไม่แน่ใจว่าเมื่อมันเข้ามา แต่พวกเขาก็ทำท่อชิ้นที่จะทำอย่างนั้น มันเป็นเอกสารที่ดีเช่นกัน

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>

4
ถ้าคุณใช้trackBy อินเตอร์เฟซ;ต้องท่อชิ้นก่อนที่จะนำไปใช้ เช่น:*ngFor="let feature of content?.keyFeatures | slice:1:5; trackBy feature?.id"
Philip

11

คุณสามารถใช้สิ่งต่อไปนี้:

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

1
สิ่งนี้จะไม่เข้าสู่เทมเพลตสำหรับทุกรายการในรายการแทนที่จะเป็นเพียงรายการที่กรองหรือไม่ นั่นอาจเป็นผลงานยอดเยี่ยม
Azeroth2b

8

ท่อใน 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 | เงื่อนไข}} จะกลับมาitemหากเงื่อนไขตรงและไม่มีค่าหากไม่ได้
Ben Glasser

@BenGlasser ฉันคิดว่ามีการนำไปใช้กับท่อจากขวาไปซ้าย ดังนั้นนี่จะใช้ filter2 ก่อนจากนั้นกรอง 1
Evan Plaice

12
*ngForและ*ngIfไม่สนับสนุนองค์ประกอบเดียวกัน คุณต้องเปลี่ยนเป็นรูปแบบที่ชัดเจนสำหรับหนึ่งในนั้น<template ngFor ...>
GünterZöchbauer

1
@ GünterZöchbauerฉันใช้เวลาหนึ่งปี แต่ฉันได้อัปเดตไวยากรณ์เพื่อให้สอดคล้องกับการเปลี่ยนแปลงที่คุณแนะนำ
Ben Glasser

5

สำหรับความต้องการนี้ผมใช้และเผยแพร่องค์ประกอบทั่วไป ดู

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>

การกรองในฟิลด์ต้นไม้ - ฟิลด์ 'Valor' ในระดับ 2 หรือ 'Valor' ในระดับ 1 หรือ 'Nome' ในระดับ 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>

การกรองฟิลด์ที่ไม่มีอยู่ - 'ความกล้าหาญ' ในระดับที่ไม่มีอยู่ 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>

ส่วนนี้ทำงานร่วมกับระดับคุณลักษณะที่ไม่มีที่สิ้นสุด ...


สวัสดีฉันอยู่ที่นี่และฉันได้ทำตามทุกขั้นตอนและในกรณีนี้ฉันใช้สิ่งนี้*ngFor="let inovice of invoices | filter:searchInvoice"และกำลังค้นหารายการของฉัน แต่แสดงรายการเปล่าคุณรู้หรือไม่ว่าทำไม
jecorrales

1
สวัสดีโปรดบอกฉันว่าโครงสร้างและประเภทของวัตถุที่รายการใบแจ้งหนี้ของคุณมีอะไรบ้าง วิธีที่คุณใช้งานนั้นควรจะใช้ได้ก็ต่อเมื่อรายการใบแจ้งหนี้ของคุณเป็นสตริงประเภท หากคุณต้องการที่จะค้นหาจากจำนวนใบแจ้งหนี้ (invoice.number) ใช้นี้* ngFor = "ให้ inovice ของใบแจ้งหนี้ | กรอง: {ฟิลด์: หมายเลขค่า: searchInvoice}" หากคุณต้องการกรองสองคอลัมน์ตัวอย่างเช่นinvoice.customer.name ให้ใช้: * ngFor = "อนุญาต inovice ของใบแจ้งหนี้ | ตัวกรอง: [ฟิลด์: หมายเลข, ค่า: searchInvoice}, {field: customer.name, value: searchInvoice}] .
Wedson Quintanilha da Silva

4

ทางออกง่าย ๆ ที่ทำงานร่วมกับ Angular 6 สำหรับการกรอง ngFor มีดังต่อไปนี้:

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

ช่วงมีประโยชน์เพราะไม่ได้เป็นตัวแทนของสิ่งใด


1
ดีกว่า <span> คือการใช้ <ng-container> เนื่องจากจะไม่เพิ่มมาร์กอัพที่ไม่จำเป็นซึ่งนอกเหนือจากเสียง html อาจส่งผลกระทบต่อ CSS ของคุณ
Trevor de Koekkoek

4

ฉันรู้ว่ามันเป็นคำถามเก่า แต่ฉันคิดว่ามันอาจเป็นประโยชน์ในการเสนอวิธีแก้ไขปัญหาอื่น

เทียบเท่ากับ 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") แบบมีเงื่อนไขในแอปพลิเคชันของคุณ แต่ไม่ต้องการล้อมด้วยองค์ประกอบอื่น


4

ฉันสร้างพลั่วเกอร์ขึ้นจากคำตอบที่นี่และที่อื่น ๆ

นอกจากนี้ผมต้องเพิ่ม@Input, @ViewChildและElementRefของ<input>และสร้างและsubscribe()ต่อไปยังสังเกตได้จากมัน

ตัวกรองการค้นหา Angular2: PLUNKR (อัพเดต: ผู้รวบรวมไม่ทำงานอีกต่อไป)


3

ท่อจะเป็นวิธีที่ดีที่สุด แต่ต่ำกว่าหนึ่งก็จะทำงาน

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

สิ่งนี้สามารถทำลายบางสิ่งได้ ตัวอย่างเช่นภายใน mat-form-field
pcnate

2

นี่คือรหัสของฉัน:

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

อีกวิธีหนึ่งที่ฉันต้องการใช้สำหรับตัวกรองเฉพาะแอปพลิเคชันคือการใช้คุณสมบัติแบบอ่านอย่างเดียวที่กำหนดเองในองค์ประกอบของคุณซึ่งช่วยให้คุณสามารถสรุปแคปเจอร์ตรรกะการกรองได้อย่างชัดเจนกว่าการใช้ไพพ์แบบกำหนดเอง (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
วิธีนี้จะไม่ทำการตรวจสอบที่สกปรกอย่างต่อเนื่องแทนที่จะใช้วิธีการเปลี่ยนค่าหรือไม่
Léon Pelletier

1

ฉันสร้างไปป์ต่อไปนี้เพื่อรับไอเท็มที่ต้องการจากรายการ

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

เป็นการดีที่คุณควรสร้าง angualr 2 ไปป์ แต่คุณสามารถทำเคล็ดลับนี้

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

1

ขึ้นอยู่กับโซลูชันท่อโทรกลับที่หรูหรามากที่เสนอไว้ด้านบนเป็นไปได้ที่จะทำให้เป็นเรื่องทั่วไปมากขึ้นอีกเล็กน้อยโดยอนุญาตให้ส่งผ่านพารามิเตอร์ตัวกรองเพิ่มเติม จากนั้นเรามี:

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

ต่อไปนี้เป็นตัวอย่างที่ฉันสร้างขึ้นมาครู่หนึ่งและบล็อกซึ่งรวมถึงการทำงานที่ไม่สมบูรณ์ มันมีท่อกรองที่สามารถกรองรายการของวัตถุใด ๆ โดยทั่วไปคุณเพียงระบุคุณสมบัติและค่า {key: value} ภายในข้อกำหนด ngFor ของคุณ

มันไม่แตกต่างจากคำตอบของ @ NateMay มากนักยกเว้นว่าฉันจะอธิบายในรายละเอียดที่ค่อนข้างละเอียด

ในกรณีของฉันฉันกรองรายการที่ไม่เรียงลำดับในข้อความ (filterText) ที่ผู้ใช้ป้อนต่อคุณสมบัติ "ป้ายกำกับ" ของวัตถุในอาร์เรย์ของฉันด้วยการเรียงลำดับนี้:

<ul>
  <li *ngFor="let item of _items | filter:{label: filterText}">{{ item.label }}</li>
</ul>

https://long2know.com/2016/11/angular2-filter-pipes/


0

ขั้นตอนแรกที่คุณสร้างตัวกรองโดยใช้ @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.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 loop Filter ของคุณโดย:

<input type="text" [(ngModel)]='filterText' />
    <ul *ngFor='let product of filterProduct'>
      <li>{{product.name }}</li>
    </ul>

ที่นั่นฉันใช้ตัวกรองผลิตภัณฑ์ทันทีเนื่องจากฉันต้องการเก็บรักษาข้อมูลดั้งเดิมของฉัน นี่ model _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

หลังจากบาง googling ng2-search-filterฉันมาข้าม ในจะนำวัตถุของคุณและใช้คำค้นหากับคุณสมบัติวัตถุทั้งหมดที่มองหาการจับคู่


0

ฉันค้นหา somethig เพื่อให้ตัวกรองผ่าน Object จากนั้นฉันสามารถใช้มันเหมือนกับ multi-filter: ตัวอย่างตัวกรองหลายตัว

ฉันทำโซลูชันความงามนี้:

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">...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.