title: Angular material : mat-table multiple column filter on dynamic data
body: <p>I am using Angular material table , displaying dynamic data which I am getting from backend. Single column search works fine . Now I would like to implement multi column search . Can anyone please help me how to achieve this?</p>
  <p>Html</p>
  <pre><code>&lt;div &gt;
    &lt;ng-container *ngIf=&quot;columns &amp;&amp; columns.length&quot;&gt;
      &lt;table mat-table matTableExporter [dataSource]=&quot;dataSource&quot; #exporter=&quot;matTableExporter&quot;&gt;
        &lt;!-- actions --&gt;
        &lt;ng-container matColumnDef=&quot;actions&quot;&gt;
  
          &lt;th mat-header-cell *matHeaderCellDef&gt;
            Update
            &lt;/th&gt;
  
          &lt;td class=&quot;trendCol icons&quot; mat-cell *matCellDef=&quot;let element;&quot;&gt;
            &lt;button mat-icon-button  style=&quot;margin:5px;&quot; color=&quot;accent&quot; (click)=&quot;navigateToTrendEdit(element.unique_id)&quot;&gt;
              &lt;mat-icon aria-label=&quot;Edit&quot;&gt;edit&lt;/mat-icon&gt;
            &lt;/button&gt;
  
            &lt;button mat-icon-button style=&quot;margin:5px;&quot; color=&quot;accent&quot; (click)=&quot;deleteItem(element.unique_id)&quot;&gt;
              &lt;mat-icon aria-label=&quot;Delete&quot;&gt;delete&lt;/mat-icon&gt;
            &lt;/button&gt;
          &lt;/td&gt;
        &lt;/ng-container&gt;
        &lt;ng-container *ngFor=&quot;let column of columns; let i = index&quot; [matColumnDef]=&quot;column.columnDef&quot;&gt;
          &lt;th mat-header-cell *matHeaderCellDef&gt;
            {{ column.header }}
            &lt;mat-icon class=&quot;filter_icon&quot; (click)=&quot;openFilterDynamic(i)&quot;
              &gt;filter_alt&lt;/mat-icon
            &gt;&lt;br&gt;
            &lt;div *ngIf=&quot;openId === i&quot;&gt;
              &lt;mat-form-field&gt;
                &lt;input
                  matInput
                  type=&quot;text&quot; [(ngModel)]=&quot;searchValue&quot;
                  class=&quot;form-field&quot;
                  (ngModelChange)=&quot;onSearchChange(column.columnDef)&quot;
                /&gt;
                &lt;button mat-button *ngIf=&quot;searchValue&quot; matSuffix mat-icon-button aria-label=&quot;Clear&quot; (click)=&quot;closeSearch(column.columnDef)&quot;&gt;
                  &lt;mat-icon&gt;close&lt;/mat-icon&gt;
                &lt;/button&gt;
              &lt;/mat-form-field&gt;
            &lt;/div&gt;
          &lt;/th&gt;
          &lt;td class=&quot;trendCol&quot; mat-cell *matCellDef=&quot;let row&quot;&gt;
            &lt;div class=&quot;tooltip&quot;&gt;
              &lt;span class=&quot;userRecord&quot;&gt;{{ column.cell(row) }}&lt;/span&gt;
              &lt;span class=&quot;tooltiptext&quot;&gt;{{ column.cell(row) }}&lt;/span&gt;
            &lt;/div&gt;
          &lt;/td&gt;
        &lt;/ng-container&gt;
        &lt;tr mat-header-row *matHeaderRowDef=&quot;dynamicColumns&quot;&gt;&lt;/tr&gt;
        &lt;tr mat-row *matRowDef=&quot;let row; columns: dynamicColumns&quot;&gt;&lt;/tr&gt;
      &lt;/table&gt;
      &lt;mat-paginator
      [pageSize]=&quot;6&quot;
      [pageSizeOptions]=&quot;[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20]&quot;
      showFirstLastButtons
      &gt;
      &lt;/mat-paginator&gt;
      &lt;div class=&quot;downloadDiv&quot;&gt;
        Download as :
        &lt;button style=&quot;margin:5px;&quot; mat-raised-button (click)=&quot;exporter.exportTable('xlsx')&quot;&gt;Excel&lt;/button&gt;
        &lt;button style=&quot;margin:5px;&quot; mat-raised-button (click)=&quot;exporter.exportTable('csv')&quot;&gt;Csv&lt;/button&gt;
        &lt;button style=&quot;margin:5px;&quot; mat-raised-button (click)=&quot;exporter.exportTable('json')&quot;&gt;Json&lt;/button&gt;
        &lt;button style=&quot;margin:5px;&quot; mat-raised-button (click)=&quot;exporter.exportTable('txt')&quot;&gt;Txt&lt;/button&gt;
      &lt;/div&gt;
    &lt;/ng-container&gt;
  &lt;/div&gt;
  </code></pre>
  <p>TS</p>
  <pre><code>import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
  import { MatTableDataSource } from '@angular/material/table';
  import { MatPaginator } from '@angular/material/paginator';
  import {MatDialog} from '@angular/material/dialog';
  import { Router } from '@angular/router';
  import {BehaviorSubject} from 'rxjs';
  
  @Component({
    selector: 'app-trends-list',
    templateUrl: './trends-list.component.html',
    styleUrls: ['./trends-list.component.scss'],
  })
  export class TrendsListComponent implements OnInit, AfterViewInit {
    
    index: number;
    id: string;
  
    dataChange: BehaviorSubject&lt;TrendsForView[]&gt; = new BehaviorSubject&lt;TrendsForView[]&gt;([]);
    
    public dataSource = new MatTableDataSource&lt;TrendsForView&gt;();
  
    globalFilter = '';
  
    @ViewChild(MatPaginator, {static: false})
    set paginator(value: MatPaginator) {
      this.dataSource.paginator = value;
    }
    
    columns: Array &lt; {
      columnDef: string;
      header: string;
      cell: (element: any) =&gt; any;
    } &gt; = [];
    dynamicColumns = ['actions', ...this.columns.map(c =&gt; c.columnDef)];
    searchValue = '';
    openId: number;
    constructor(private router: Router, private _router: Router,private trendsService: TrendsService, public dialog: MatDialog) {}
  
    ngOnInit(): void {
      this.getAllTrends();
      this.dataSource.filterPredicate = this.customFilterPredicate();
    }
  
    onSearchChange(key: string) {
      this.dataSource.filter = JSON.stringify({key, value: this.searchValue.toLowerCase()});
    }
    closeSearch(key: string) {
      this.searchValue = '';
      this.dataSource.filter = JSON.stringify({key, value: this.searchValue.toLowerCase()});
    }
  
    customFilterPredicate() {
      const myFilterPredicate = (
        data: TrendsForView,
        filter: string
      ): boolean =&gt; {
        let searchString = JSON.parse(filter);
        if (this.searchValue) {
          return data[searchString.key].toString().trim().toLowerCase().indexOf(searchString.value) !== -1;
        } else {
          return true;
        }
       
      }
      return myFilterPredicate;
    }
    ngAfterViewInit(): void {
      this.dataSource.paginator = this.paginator;
    }
    public getTrends = () =&gt;{
      this.trendsService.getTrend().subscribe((res) =&gt; {
        this.dataSource.data = res.all_docs;
      });
    };
    public getAllTrends = () =&gt; {
      this.trendsService.getTrend().subscribe((res) =&gt; {
        this.dataSource.data = res.all_docs;
        const columns = this.dataSource.data[0];
              if (columns) {
          Object.keys(columns).forEach((key) =&gt; {
            if(key!=&quot;unique_id&quot;){
              this.columns.push({
                header: key.replace(/_/g, ' '),
                columnDef: key,
                cell: (element: any) =&gt; element[key]
              });
            }
          });
          this.dynamicColumns = ['actions', ...this.columns.map(c =&gt; c.columnDef)];
        }
      });
    };
    openFilterDynamic(index: number) {
      this.openId = (this.openId === index) ? undefined : index;
      this.closeSearch('')
    }
  
    public redirectToDetails = (id: string) =&gt; {
      this.router.navigate(['/home']);
    };
  
    navigateToTrendEdit(id: any){
      this._router.navigateByUrl('/home' + id);
    }
  
    deleteItem(id: any){
      this.openDialog(id);
    }
  
    openDialog(id: any) {
      const dialogRef = this.dialog.open(DeleteTrendDialogComponent,{
        data: {
          message: id
        }
      });
  
      dialogRef.afterClosed()
            .subscribe(result =&gt; {
              if (result === 'closed') {
                this.getTrends();
           }
            });
  
  
    }
  }
  </code></pre>
  <p>As I told single column search works fine , but I am stuck on how to do multi column search.</p>