Filtering specific column in Angular Material Table with filtering in angular?

Adding to bugs' answer. Here's a more elaborate implementation,

export class FilterTable implements AfterViewInit {
  //some datasource
  datasource //=
  displayedColumns //=insert column names on which you want to filter whether they are displayed or not, but present in the datasource

  // Apply filter to the datasource
  applyFilter(filterValue: string) {
    this.datasource.filter = filterValue;
  }


  ngAfterViewInit() {
    // Overwriting filterPredicate here, as it needs to be done after the datasource is loaded.
    this.datasource.filterPredicate = (data, filter) => {
      var tot = false;
      for (let column of this.displayedColumns) {
        //incase if there is a date type and is displayed differently using a pipe, then convert it intorequired format before filtering
        //check if all the columnson which you are filtering are actually present
        if ((column in data) && (new Date(data[column].toString()).toString() == "Invalid Date")) {
          //if not date column
          tot = (tot || data[column].toString().trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1);
        } else {
          //change this to the format in which date is displayed
          var date = new Date(data[column].toString());
          var m = date.toDateString().slice(4, 7) + " " + date.getDate() + " " + date.getFullYear();
          tot = (tot || m.toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1);
        }
      }
      return tot;
    }
  }
}

Please feel free to suggest edits, if this could be improved


Material has implemented its own search feature you can override it by updating the filterPredicate property on the date source. Call the generateTable function on ngOninit() life cycle.

generateTable(tableData: any) {
    this.dataSource = new MatTableDataSource(tableData);
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
    this.dataSource.filterPredicate = (data: any, filter: string) => {
      console.log(data);
      console.log(filter);
      let matchFound = false;
      for (let column of this.displayedColumns) {
        if(column in data) {
          if(data[column]) {
            matchFound = (matchFound || data[column].toString().trim().toLowerCase().indexOf(filter.trim().toLowerCase()) !== -1)
          }
        }
      }
      return matchFound;
    }
  }

Whenever you wish to apply the filter, update the filter property on dataSource to the string value to be searched.

applyFilter(searchValue: any) {
    this.dataSource.filter = this.filterText.trim().toLowerCase();
    }

You have to override the filterPredicate of your dataSource.

Here's an example of how to do it: Working demo


Essentially, you want to specify what properties in your data the filter is applied to:

this.dataSource.filterPredicate = function(data, filter: string): boolean {
    return data.name.toLowerCase().includes(filter) || data.symbol.toLowerCase().includes(filter) || data.position.toString().includes(filter);
};

In Angular Material Tables, we can create column based filters from data itself.

Source Link

Demo Link

enter image description here

For that, we need to override the filterPredicate method with customFilter() method

        ...
        ngOnInit() {
            this.getRemoteData();

            // 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
        }

Check complete working code here