1

I've been trying to apply multi column filtering i.e a text input in column headers will filter only on the contents of the column. So far I tried to filter client_name and module_controle columns but that doesn't seem to work, I lose all my array data (I have an empty array). I have no error in my console.

Here is my code home.component.html:

 <table mat-table [dataSource]="dataSource" matSort>

      <ng-container matColumnDef="module_control">
        <th mat-header-cell *matHeaderCellDef >Module control
          <div>
            <mat-form-field>
              <input matInput class="form-field" [formControl]="moduleControlFilter" placeholder="Filter" (click)="$event.stopPropagation()"/>
            </mat-form-field>
          </div>
        </th>
        <td mat-cell *matCellDef="let element"> {{element.module_control}} </td>
      </ng-container>

      <ng-container matColumnDef="client_name">
        <th mat-header-cell *matHeaderCellDef >Client name
          <div>
            <mat-form-field>
              <input matInput class="form-field" [formControl]="clientNameFilter" placeholder="Filter" (click)="$event.stopPropagation()"/>
            </mat-form-field>
          </div>
        </th>
        <td mat-cell *matCellDef="let element"> {{element.client_name}} </td>
      </ng-container>

          ......

      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
    </table>

Home.component.ts:

export class HomeComponent implements OnInit {

  displayedColumns: string[] = ['module_control', "client_name"];
  customers!: Customer[];

  dataSource = new MatTableDataSource<Customer>(this.customers)

  clientNameFilter = new FormControl();
  moduleControlFilter = new FormControl();

  filteredValues = { 
    client_name: '',
    module_control: '',
  }

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) matSort! : MatSort;

  constructor(private customerService: customerService) { }

  ngOnInit() {
    this.moduleControlFilter.valueChanges.subscribe((moduleControlFilterValue) => {
      this.filteredValues['module_control'] = moduleControlFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    this.clientNameFilter.valueChanges.subscribe((ClientNameFilterValue) => {
      this.filteredValues['client_name'] = ClientNameFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });


    this.dataSource.filterPredicate = this.filterTable()

    this.customerService.getAllCustomers().subscribe(
      customers => {
        this.customers = customers;
        this.dataSource = new MatTableDataSource<Customer>(this.customers);
        this.dataSource.paginator = this.paginator;
      },
      (error: HttpErrorResponse) => {
        console.log(error.message);
      })
  }

  applyFilter(filterValue: string)
  {
    this.dataSource.filter = filterValue.trim().toLowerCase();
    this.dataSource.filter = filterValue;
  }

  filterTable() {
    const myFilterPredicate = function(data: Customer, filter: string): boolean 
    {
      let searchString = JSON.parse(filter);
      return (
        data?.module_control?.toString().trim().toLowerCase().indexOf(searchString.module_control.toLowerCase()) !== -1 &&
        data?.client_name?.toString().trim().toLowerCase().indexOf(searchString.client_name.toLowerCase()) !== -1
      );
    };
    return myFilterPredicate;
  }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Daemes
  • 14,239
  • 3
  • 6
  • 13
  • you should toLowerCase when give value to filteredValues:`this.filteredValues['module_control'] = moduleControlFilterValue.toLowerValue();` && `this.filteredValues['client_name'] = ClientNameFilterValue.toLowerValue();` NOTE: you can use `this.filteredValues.client_name = ClientNameFilterValue.toLowerValue();` NOTE2: you can also create a formGroup and only subscribe to the formGroup. you can see an example in this another [SO](https://stackoverflow.com/questions/75374514/search-filter-in-a-material-angular-table-for-each-column/75374975#75374975) – Eliseo Feb 14 '23 at 16:15

1 Answers1

1

When you get the data you create a new DataSource in the subscription. It replace this.dataSource.filterPredicate value. It means that MatTable will use default own filter. But this filter gets JSON insead of simple string and can't find nothing like {"client_name":"","module_control":"2"}.

Your filterTable() wasn't used at all. You can check this, if filterTable function return true everywhere, it will not give any result.

So, you should add declaration of filterPredicate to your data subscription(or valueChange subscription)

this.customerService.getAllCustomers().subscribe(
      customers => {
        this.customers = customers;
        this.dataSource = new MatTableDataSource<Customer>(this.customers);
        this.dataSource.paginator = this.paginator;
        this.dataSource.filterPredicate = this.filterTable(); // filter function was added
      },
      (error: HttpErrorResponse) => {
        console.log(error.message);
      })
rofrol
  • 14,438
  • 7
  • 79
  • 77
Nikita
  • 682
  • 2
  • 13