1

I am using the example Table with filtering from Angular Material's site https://material.angular.io/components/table/examples

I want to let users search using wildcards. In this case, a %

I wrote the following:

    const filterValue = (event.target as HTMLInputElement).value;

    let filterArray = filterValue.trim().toLowerCase().split("%");

    for (let fil of filterArray) {
      //I know this line below won't work, as it will just replace the filter with each iteration, but showing for sake of example
      this.tableData.filter = fil;
      
    }

So if the user types one%two in the input field, I would want the filter to find table rows where both the words "one" AND "two" exist somewhere in the row.

I have tried several variations of code, but nothing seems to work quite right. Any ideas on how to make this work?

ts1993
  • 107
  • 2
  • 12

2 Answers2

1

You have to override the default implementation of this.dataSource.filterPredicate like this:

constructor() {
    this.dataSource.filterPredicate = ((data, filters) => {
      let match = false;
      const filtersList = JSON.parse(filters);

      filtersList.forEach(filterObj => {
        match =
          match || !filterObj ||
          Object.values(data)
            .map(t => t.toLocaleString().toLocaleLowerCase())
            .includes(filterObj);
      });
      return match;
    }) as (PeriodicElement, string) => boolean;
  } 

And in your applyFilter method you need pass array to filterPredicate by JSON.stringify(filterArray); like this:

applyFilter(filterValue: KeyboardEvent) {
    let filterArray = (filterValue.target as any).value
      .trim()
      .toLowerCase()
      .split('%');
    this.dataSource.filter = JSON.stringify(filterArray);
  } 

Here is full working example I wrote for you.

enter image description here

Alireza Ahmadi
  • 8,579
  • 5
  • 15
  • 42
  • The stackblitz example looks great. However in my app I am creating the table once I receive data via ngOnChanges. I tried to set the filter predicate at that point but I keep getting an error `Cannot read property 'toLocaleString' of null` I also tried to set an empty matTableDataSource and set the filter predicate in the constructor like the example and it doesn't throw errors, but no data ever gets returned once anything is entered in the search. – ts1993 Jun 18 '21 at 20:12
  • Please put your code in stackblitz to debug that. – Alireza Ahmadi Jun 19 '21 at 04:46
  • @ts1993 It seems that `data` in null. It's good to `console.log(data)` in `filterPredicate ` method – Alireza Ahmadi Jun 19 '21 at 06:37
1

I was able to accomplish this by using the following code in my applyFilter() method:

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;

    let filterArray = filterValue.trim().toLowerCase().split("%");

    let filteredData = [];

    //loop through each word provided in the filter and push matching arrays from the dataset to filterdData temporary holder
    for (let str of filterArray) {
      filteredData.push(
        this.data.filter((o) =>
          Object.keys(o).some((k) => String(o[k]).toLowerCase().includes(str))
        )
      );
    }

    //filter down final dataset with array items that occur in each array producded by each search term provided
    filteredData = filteredData.reduce((a, b) =>
      a.filter((c) => b.includes(c))
    );

    this.tableData.data = filteredData;
  }

I was able to pull information from each of these questions to form a solution that fit my needs:

ts1993
  • 107
  • 2
  • 12