LeO
LeO

Reputation: 5238

Material table - trigger filter programatically

Following this sample I know I can write my own this.dataSource.filterPredicate. This works fine as long as I search for a string. I want to filter additionally according to a used state (=myFilterState).

I try to use the predicate like

this.dataSource.filterPredicate = 
    (data: MyElement, filter: string) => data.myType.useState === this.myFilterState;

The problem I'm facing is that when I change this.myFilterState the filter is not reevaluated until I change the string of the filter. As long as the filter remains empty the filterPredicate is not triggered.

Is there a way to trigger it manually - despite the value of filter?

Upvotes: 2

Views: 1257

Answers (2)

scottfrenz
scottfrenz

Reputation: 51

Warning and additional solution when using a paginator for LeO's solution

LeO's answer is very helpful, but be careful when overriding methods of a class. I tried their solution, and it worked for filtering, but my associated paginator with the table would ALWAYS show 0/0 items, even though it would correctly show the desired number of rows.

Tl;dr Add these lines before the return statement in LeO's answer

if (this.dataSource.paginator) {
    this.dataSource._updatePaginator(this.dataSource.filteredData.length);
  }

After spending hours trying to figure out why the paginator always displayed 0/0, I eventually ran across someone with an unrelated problem who had explicitly put

 [length]="dataSource.filteredData.length"

in their mat-paginator html tag. When I inserted this attribute, the display showed the correct values.

I then looked at angular's table-data-source.ts source code for the _filterData method at it had these lines (lines 325-327):

if (this.paginator) {
  this._updatePaginator(this.filteredData.length);
}

I added these lines in the block of code from LeO's answer and got it to work properly without needing the length attribute of the html tag:

  if (this.dataSource.paginator) {
    this.dataSource._updatePaginator(this.dataSource.filteredData.length);
  }

Upvotes: 1

LeO
LeO

Reputation: 5238

After investigation of the problem I figured out that the filterpredicate is triggered by the source code only when the filter has a value. Otherwise it won't be triggered.

Therefore I come up with the solution to overwrite the internal _filterData with

this.dataSource._filterData = (data: PropertyCompact[]) => {
        this.dataSource.filteredData = data.filter(obj => this.dataSource.filterPredicate(obj, this.dataSource.filter));
            return this.dataSource.filteredData;
        };

and in case of an change one needs to trigger an update

this.dataSource._updateChangeSubscription();

Upvotes: 5

Related Questions