angular - ¿Cómo aplicar filtros a *ngFor?
Aparentemente, Angular 2 usará pipes en lugar de filtros como en Angular1 junto con ng-for para filtrar resultados, aunque la implementación aún parece ser vaga, sin documentación clara.
Es decir, lo que estoy intentando lograr podría verse desde la siguiente perspectiva
<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>
¿Cómo implementar eso usando tuberías?
Respuesta #1
Básicamente, escribes un pipe que luego puedes usar en la directiva *ngFor.
En tu componente:
filterargs = {title: 'hello'};
items = [{title: 'hello world'}, {title: 'hello kitty'}, {title: 'foo bar'}];
En tu plantilla, puedes pasar una cadena, un número u objeto a tu pipe para usarlo en el filtrado:
<li *ngFor="let item of items | myfilter:filterargs">
En tu tubería:
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);
}
}
Recuerda registrar tu pipe en app.module.ts; ya no necesitas registrar los pipes en tu @Component
import { MyFilterPipe } from './shared/pipes/my-filter.pipe';
@NgModule({
imports: [
..
],
declarations: [
MyFilterPipe,
],
providers: [
..
],
bootstrap: [AppComponent]
})
export class AppModule { }
Aquí hay un Plunker que muestra el uso de un filtro personalizado y del pipe incorporado slice para limitar los resultados.
Tenga en cuenta (como varios comentaristas han señalado) que hay una razón por la cual no hay filtros incorporados en Angular.
Respuesta #2
Muchos de ustedes tienen excelentes enfoques, pero el objetivo aquí es ser genérico y definir un pipe de array que sea extremadamente reutilizable en todos los casos en relación con *ngFor.
callback.pipe.ts (no olvides agregar esto al array de declaraciones de tu módulo)
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));
}
}
Luego, en tu componente, necesitas implementar un método con la siguiente firma (item: any) => boolean, en mi caso, por ejemplo, lo llamé filterUser, que filtra la edad de los usuarios que son mayores de 18 años.
Tu Componente
@Component({
....
})
export class UsersComponent {
filterUser(user: IUser) {
return !user.age >= 18
}
}
Y por último, pero no menos importante, tu código html se verá así:
Tu HTML
<li *ngFor="let user of users | callback: filterUser">{{user.name}}</li>
Como puedes ver, este Pipe es bastante genérico para todos los elementos similares a un array que necesitan ser filtrados mediante un callback. En mi caso, lo encontré muy útil para escenarios similares a *ngFor.
¡Espero que esto ayude!
codematrix
Respuesta #3
Esto es lo que implementé sin usar pipe.
componente.html
<div *ngFor="let item of filter(itemsList)">
componente.ts
@Component({
....
})
export class YourComponent {
filter(itemList: yourItemType[]): yourItemType[] {
let result: yourItemType[] = [];
//your filter logic here
...
...
return result;
}
}
Respuesta #4
Forma simplificada (Se utiliza solo en arreglos pequeños debido a problemas de rendimiento. En arreglos grandes, tienes que hacer el filtro manualmente mediante código):
Ver: 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);
}
}
Uso :
<li *ngFor="let it of its | filter : 'name' : 'value or variable'">{{it}}</li>
Si usas una variable como segundo argumento, no uses comillas.
Respuesta #5
No estoy seguro de cuándo llegó, pero ya hicieron un tubo de corte que hará eso. También está bien documentado.
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>
Respuesta #6
Una solución simple que funciona con Angular 6 para filtrar un ngFor, es la siguiente:
<span *ngFor="item of itemsList" >
<div *ngIf="yourCondition(item)">
your code
</div>
</span>Los spans son útiles porque no representan nada de manera inherente.
Respuesta #7
También podrías usar lo siguiente:
<template ngFor let-item [ngForOf]="itemsList">
<div *ng-if="conditon(item)"></div>
</template>
Esto solo mostrará el div si tus elementos cumplen con la condición
Consulta la documentación de Angular para más información. Si también necesitas el índice, utiliza lo siguiente:
<template ngFor let-item [ngForOf]="itemsList" let-i="index">
<div *ng-if="conditon(item, i)"></div>
</template>
