1
votes

I want to filter a column in an Angular Material table for multiple values.

This is what my table looks like

I have added two filters on this. A dropdown filter for position with checkboxes corresponding to each position and a text based filter for the name. I want the filter to work in such a way that if I click the checkbox for 1 and 10 in the position dropdown, both the rows are visible. But, if I write H in the name filter when those 2 checkboxes are ticked, only row 1 is visible. Basically, an OR in the multiple filters of one column and an AND between the filters of different columns.

Right now, my code works for the AND part between the two separate filters. However, if I select two checkboxes in the position dropdown menu, neither column is visible.

Attaching my code on Stackblitz for reference

2

2 Answers

5
votes

I have changed some codes in customFilterPredicate

customFilterPredicate() {
    return (data: PeriodicElement, filter: string): boolean => {
      let searchString = JSON.parse(filter) as MyFilter;
      let isPositionAvailable = false;
      if (searchString.position.length) {
        for (const d of searchString.position) {
          // equal validate
          if (data.position.toString().trim() == d) {
          // OR
          // Checking index of
          if (data.position.toString().trim().indexOf(d) !== -1) {
            isPositionAvailable = true;
          }
        }
      } else {
        isPositionAvailable = true;
      }
      return isPositionAvailable && data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1;
    }
  }

Add some interface for better typing

export interface MyFilter {
  position: string[],
  name: string,
  weight: string,
  symbol: string
}

Also add interface in filteredValues

filteredValues: MyFilter = { position: [], name: '', weight: '', symbol: '' };
0
votes

You can simply filter the data yourself and set the data of dataSource. Like following code.

Method for filtering the options.

filterOptions(positionValue: string[], nameValue: string): PeriodicElement[] {
  if ((!positionValue || positionValue.length === 0)  && !nameValue) {
    return ELEMENT_DATA;
  }
  const filtered = ELEMENT_DATA.filter((periodicElement) => {
    return (nameValue? periodicElement.name.toLowerCase().includes(nameValue.toLowerCase()): false) 
           || (positionValue ? positionValue.indexOf(periodicElement.position+'') !==-1: false)});
      return filtered;
}

You can use this on both filter change like following

this.positionFilter.valueChanges.subscribe((positionFilterValue)        => {
 this.dataSource.data = this.filterOptions(positionFilterValue, this.nameFilter.value);
});

this.nameFilter.valueChanges.subscribe((nameFilterValue) => {
  this.dataSource.data = this.filterOptions(this.positionFilter.value, nameFilterValue);
});

Here is your updated code with above changes https://stackblitz.com/edit/angular-hbakxo-e4njon