web-dev-qa-db-fra.com

Filtres multiples sur MatTable

J'ai essayé d'appliquer un filtrage multi-colonnes, c'est-à-dire qu'une entrée de texte dans les en-têtes de colonne ne filtrerait que le contenu de la colonne. Jusqu'à présent, j'ai pu le faire fonctionner en remplaçant filterPredicate of MatTableDataSource mais une fois que j'ai outrepassé le filtrage par défaut qui est à travers les colonnes ne fonctionne plus.

export class TableFilteringExample implements OnInit
{
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = new MatTableDataSource(ELEMENT_DATA);

  positionFilter = new FormControl();
  nameFilter = new FormControl();

  filteredValues =
  {
    position: '',
    name: '',
    weight: '',
    symbol: ''
  };

  ngOnInit()
  {
    this.positionFilter.valueChanges.subscribe((positionFilterValue) =>
    {
      this.filteredValues['position'] = positionFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    this.nameFilter.valueChanges.subscribe((nameFilterValue) =>
    {
      this.filteredValues['name'] = nameFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    this.dataSource.filterPredicate = this.customFilterPredicate();
  }

  applyFilter(filterValue: string)
  {
    this.dataSource.filter = filterValue.trim().toLowerCase();
    this.dataSource.filter = filterValue;
  }

  customFilterPredicate()
  {
    const myFilterPredicate = function(data: PeriodicElement, filter: string): boolean
    {
      let searchString = JSON.parse(filter);

      return data.position.toString().trim().indexOf(searchString.position) !== -1 && data.name.toString().trim().toLowerCase().indexOf(searchString.name)!== -1;
    }

    return myFilterPredicate;
  }
}

Ce que je recherche, c'est qu'une fois le filtre de colonne appliqué, le filtre par défaut doit mettre à jour les critères de filtre existants et renvoyer les données filtrées supplémentaires.

StackBlitz

6
kal93

Je pense que vous avez juste oublié d'appeler toLowerCase() pour searchString.name

data.name.toString (). trim (). toLowerCase (). indexOf (searchString.name.toLowerCase ())! == -1;


EDIT: Une approche consiste à créer un champ de filtre global dans votre classe Component.

globalFilter = '';

<mat-form-field>
  <input matInput [ngModel]="globalFilter" (ngModelChange)="applyFilter($event)" placeholder="Filter">
</mat-form-field>

applyFilter(filter) {
    this.globalFilter = filter;
    this.dataSource.filter = JSON.stringify(this.filteredValues);
}

Essayez ensuite de filtrer à l'aide du filtre global avant les autres champs.

  customFilterPredicate() {
    const myFilterPredicate = (data: PeriodicElement, filter: string): boolean => {
      var globalMatch = !this.globalFilter;

      if (this.globalFilter) {
        // search all text fields
        globalMatch = data.name.toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1;
      }

      if (!globalMatch) {
        return;
      }

      let searchString = JSON.parse(filter);
      return data.position.toString().trim().indexOf(searchString.position) !== -1 &&
        data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1;
    }
    return myFilterPredicate;
  }

Voici l'application de travail: https://stackblitz.com/edit/angular-hbakxo-5jeaic

13
Randal Cunanan

Dans Angular Material Tables, vous pouvez ajouter un filtre multi-colonnes en utilisant la propriété filterPredicate sur les tables mat et en leur fournissant un méthode customFilter comme indiqué ci-dessous

Source Lien

Démo Lien

enter image description here

        ngOnInit() {

        // Overrride default filter behaviour of Material Datatable
        this.dataSource.filterPredicate = this.createFilter();
        }

        ...
        ...

        // Custom filter method fot Angular Material Datatable
        createFilter() {
        let filterFunction = function (data: any, filter: string): boolean {
          let searchTerms = JSON.parse(filter);
          let isFilterSet = false;
          for (const col in searchTerms) {
            if (searchTerms[col].toString() !== '') {
              isFilterSet = true;
            } else {
              delete searchTerms[col];
            }
          }

          let nameSearch = () => {
            let found = false;
            if (isFilterSet) {
              for (const col in searchTerms) {
                searchTerms[col].trim().toLowerCase().split(' ').forEach(Word => {
                  if (data[col].toString().toLowerCase().indexOf(Word) != -1 && isFilterSet) {
                    found = true
                  }
                });
              }
              return found
            } else {
              return true;
            }
          }
          return nameSearch()
        }
        return filterFunction
        }
0
Code Spy