Búsqueda de sitios web

html - Escribiendo un filtro de tabla personalizado en Angular 6


Quería agregar un filtro de tabla personalizado a mi código Angular. Hice una búsqueda en la web y encontré este artículo de blog:

https://www.code-sample.com/2018/07/angular-6-search-filter-pipe-table-by.html

Funciona bastante bien y aquí está el código de la tubería:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'gridFilter'
})

/*
 I got this code from here:
 https://www.code-sample.com/2018/07/angular-6-search-filter-pipe-table-by.html
*/

export class GridFilterPipe implements PipeTransform {
  transform(items: any, filter: any, defaultFilter: boolean): any {
    if (!filter){
      return items;
    }

    if (!Array.isArray(items)){
      return items;
    }

    if (filter && Array.isArray(items)) {
      let filterKeys = Object.keys(filter);

      if (defaultFilter) {
        return items.filter(item =>
            filterKeys.reduce((x, keyName) =>
                (x && new RegExp(filter[keyName], 'gi').test(item[keyName])) || filter[keyName] == "", true));
      }
      else {
        return items.filter(item => {
          return filterKeys.some((keyName) => {
            return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] == "";
          });
        });
      }
    }
  }
}

Funciona bastante bien para la mayoría de mis necesidades excepto esta tabla que es este html:

  <div class="col-md-4" *ngIf="element == 'location'">
    <div class="spacer"></div>
    <div class="panel panel--vibblue panel--raised">{{ element | titlecase }}</div>
    <div class="responsive-table panel--raised">
      <table class="table table--bordered table--hover approvals-table" id="location-table">
        <thead>
        <tr>
          <th class="sortable">{{ element | titlecase }} Name <span class="sort-indicator icon-chevron-down"></span></th>
          <th class="sortable">Site <span class="sort-indicator icon-chevron-down"></span></th>
          <th>Action</th>
        </tr>
        </thead>
        <tbody>
        <ng-container *ngFor="let el of elements | gridFilter: {name: searchText, site:searchText}">
          <tr>
            <td>{{el.name}}</td>
            <td>{{ getSiteName(el.site) }}</td>
            <td>
              <a><span class="icon-trash" (click)="deleteElement(el.id, el.name)"></span></a>
            </td><td>
            <a><span class="icon-pencil" (click)="editElement(el)"></span></a>
          </td>
          </tr>
        </ng-container>
        </tbody>
      </table>
    </div>
  </div>

El problema con la tabla anterior es este. Para mostrar el nombre del sitio de una ubicación, utilizo este HTML ...

<td>{{ getSiteName(el.site) }}</td>

... que llama a un método getSiteName que toma el id de un sitio y devuelve el nombre del sitio. No sé cómo configurar mi gridFilter. Así que si intento buscar el nombre de un sitio, mi gridFilter no encuentra el sitio.

Aquí está mi stackblitz para esto: https://stackblitz.com/edit/angular-damcul

** ACTUALIZACIÓN **

He actualizado mi stackblitz para ilustrar realmente el problema que estoy teniendo. Aquí hay una captura de pantalla de la aplicación stackblitz:

Puedo buscar ubicaciones y aquí está la captura de pantalla de mí buscando 'loc_2':

Pero no puedo buscar sitios. Aquí está la captura de pantalla de mí buscando cualquier 'sitio'.

Respuesta #1

hice algunos cambios:

  • en el código que compartiste en la pregunta, habías usado un filtro llamado grdFilter, en tu stackblitz era 'gridFilter'
  • Se añadió la implementación de getSiteName, que toma el objeto y devuelve el nombre del blog (no hay ninguna propiedad llamada 'site' en nuestros datos)
  • en tu código compartido en la pregunta, tenías
<ng-container *ngFor="let el of customerData | gridFilter: {name: searchText, site:searchText}">
  • ya que no hay una propiedad llamada 'site' en nuestros datos, la cambiamos a
<ng-container *ngFor="let el of customerData | grdFilter: {name: searchText, blog:searchText}">

relevante hello.component.ts:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<input [(ngModel)]="searchText" placeholder="Search.." class="advancedSearchTextbox">
<p></p>
<table *ngFor="let emp of customerData | grdFilter: {name: searchText, Age:searchText,  blog: searchText}; let i=index;">
  <tr>
    <td style="width: 5%;">{{i +1}}</td>
    <td style="width: 10%;">{{emp.name}}</td>
    <td style="width: 5%;">{{emp.Age}}</td>
    <td style="width: 15%;">{{emp.blog}}</td>
  </tr>
</table>
<hr/>
<table class="table table--bordered table--hover approvals-table" id="location-table">
  <thead>
    <tr>
      <th class="sortable">{{ element | titlecase }} Name <span class="sort-indicator icon-chevron-down"></span></th>
      <th class="sortable">Site <span class="sort-indicator icon-chevron-down"></span></th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <ng-container *ngFor="let el of customerData | grdFilter: {name: searchText, blog:searchText}">
      <tr>
        <td>{{el.name}}</td>
        <td>{{ getSiteName(el) }}</td>
        <td>
          <a><span class="icon-trash" (click)="deleteElement(el.id, el.name)"></span></a>
        </td><td>
        <a><span class="icon-pencil" (click)="editElement(el)"></span></a>
      </td>
      </tr>
    </ng-container>
  </tbody>
</table>
`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
  public searchText: string;
  public customerData: any;

  @Input() name: string;

  constructor() { }

  ngOnInit() {
    this.customerData = [
      { "name": 'Anil kumar', "Age": 34, "blog": 'https://code-view.com' },
      { "name": 'Sunil Kumar Singh', "Age": 28, "blog": 'https://code-sample.xyz' },
      { "name": 'Sushil Singh', "Age": 24, "blog": 'https://code-sample.com' },
      { "name": 'Aradhya Singh', "Age": 5, "blog": 'https://code-sample.com' },
      { "name": 'Reena Singh', "Age": 28, "blog": 'https://code-sample.com' },
      { "name": 'Alok Singh', "Age": 35, "blog": 'https://code-sample.com' },
      { "name": 'Dilip Singh', "Age": 34, "blog": 'https://code-sample.com' }];
  }
  getSiteName(passedObj) {
    return passedObj.blog;
  }
}

actualización #1 a la luz del comentario del preguntador y la pregunta actualizada:

si vas al archivo grd-pipe.ts, y haces console.log(items,filter), verás que el arreglo con el que estamos trabajando dentro del pipe personalizado es el arreglo locations, que tiene los valores de la columna 'sites' como 1, 2 o 3. El nombre del sitio que has obtenido para la IU desde el arreglo sites no forma parte del arreglo locations, y por lo tanto no puede ser procesado por el pipe.

Entonces, creamos un nuevo campo siteName en el arreglo locations donde almacenamos el nombre del sitio (del arreglo sites), ahora, dado que el campo está disponible dentro del pipe, el pipe también puede buscar en él.

cambios relevantes en TS

ngOnInit(){
for(var i=0;i<this.locations.length;i++){
        this.locations[i].siteName = this.sites.find(s => s.id === this.locations[i].site).name;
      }
}

cambios relevantes en HTML el campo agregado siteName añadido al filtro:

<table class="table table--bordered table--hover approvals-table" id="location-table">
  <tbody>
    <ng-container *ngFor="let loc of locations | grdFilter: {name: searchText, siteName:searchText}; let i=index">
      <tr>
        <td style="width: 5%;">{{i +1}}</td>
        <td style="width: 10%;">{{loc.name}}</td>
        <td style="width: 5%;">{{getSiteName(loc.site)}}</td>
      </tr>
    </ng-container>
  </tbody>
</table>

el stackblitz funcionando aquí también está actualizado

Artículos relacionados