user9450118
user9450118

Reputation:

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

I am using mat-table. It has a filter which works fine.

Filter happened against this below data (All columns)

const ELEMENT_DATA: Element[] = [
  {position: 14598, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
  {position: 24220, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 39635, name: 'Lithium', weight: 6.941, symbol: 'Li'},
  {position: 42027, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
  {position: 53216, name: 'Boron', weight: 10.811, symbol: 'B'},
  {position: 60987, name: 'Carbon', weight: 12.0107, symbol: 'C'},
  {position: 70976, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
  {position: 81297, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
  {position: 90975, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
  {position: 18879, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
  {position: 11209, name: 'Sodium', weight: 22.9897, symbol: 'Na'}

];

But Now I am trying to change the filter because I want is filter just for "position", "name", "symbol" column. I have gone through this example but Filtering specific column in Angular Material table in angular 5.

I did not understand please help me on this

StackBlitz Code

Upvotes: 28

Views: 93926

Answers (4)

an0nym0use
an0nym0use

Reputation: 341

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

Upvotes: 3

Code Spy
Code Spy

Reputation: 9964

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

Upvotes: 6

Rohan Shenoy
Rohan Shenoy

Reputation: 895

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();
    }

Upvotes: 1

bugs
bugs

Reputation: 15313

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);
};

Upvotes: 59

Related Questions