Angular Material Table Sorting with reactive formarray

Viewed 4559

I am trying to implement sorting / filtering on angular material table with formArray as input data source.

StackBlits code link

dataSource = new MatTableDataSource([]);
<table mat-table [dataSource]="formdataarray.controls" multiTemplateDataRows class="mat elevation-z8" matSort >
<ng-container  matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay" >
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{column}}</th>
<td mat-cell *matCellDef="let element"> {{ element.value[column] }}  </td>
</ng-container>

But Sorting / Filtering is not working

3 Answers

You have two options here:

  • use plain array formdataarray.controls as a dataSource and implement all DataSource methods like filter, sort by your own. Or write custom CDK DataSource implementation. See also https://blog.angular-university.io/angular-material-data-table/

  • use MatTableDataSource and adjust filtering and sorting logic to support AbstractControl object.

html

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

ts

ngOnInit() {
  // fill FormArray
  ...
  this.dataSource.data = this.formdataarray.controls;
  this.dataSource.sortingDataAccessor = (data: AbstractControl, sortHeaderId: string) => {
    const value: any = data.value[sortHeaderId];
    return typeof value === 'string' ? value.toLowerCase() : value;
  };

  const filterPredicate = this.dataSource.filterPredicate;
  this.dataSource.filterPredicate = (data: AbstractControl, filter) => {
    return filterPredicate.call(this.dataSource, data.value, filter);
  }
}

Forked Stackblitz

Also, if you want to add new items to your FormArray you should update this.dataSource.data as well. See also Angular Material editable table using FormArray

You also needs add event (matSortChange)=sortTable($event)

To the table tag

And add sortTable logic inside components

Requires ngAfterViewInit to work

import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';

...

@ViewChild(MatSort, {static: false}) sort: MatSort

...

ngOnInit() {
  this.getYourData$.subscribe(d => this.data = new MatTableDataSource(d));
}

ngAfterViewInit(): void {

  this.data.sortingDataAccessor = (data: AbstractControl, sortHeaderId: string) => {
  const value: any = data.value[sortHeaderId];
  return typeof value === 'string' ? value.toLowerCase() : value;
};

this.data.sort = this.sort; // where this.sort defined above.

  this.data.filterPredicate = (data: AbstractControl, filter) => {
  // return true or false on data.
  }
}


... html

<table matSort ...
Related