Búsqueda de sitios web

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>

Artículos relacionados