I would like to make filterPredicate
to work with empty filter string.
html:
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. ium" #input>
</mat-form-field>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Weight </th>
<td mat-cell *matCellDef="let element"> {{element.weight}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Symbol </th>
<td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [hidden]="row.disabled == true"></tr>
<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>
</table>
<div [hidden]="dataSource.paginator == null">
<mat-paginator pageSize="10" [pageSizeOptions]="[3, 5, 10]" showFirstLastButtons></mat-paginator>
</div>
ts:
import { Component, OnInit, AfterViewInit, ViewChild } from "@angular/core";
import { MatTableDataSource } from "@angular/material/table";
import { MatPaginator } from "@angular/material/paginator";
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
disabled: boolean;
}
const ELEMENT_DATA: PeriodicElement[] = [
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H', disabled: false},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He', disabled: false},
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li', disabled: false},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be', disabled: false},
{position: 5, name: 'Boron', weight: 10.811, symbol: 'B', disabled: false},
{position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C', disabled: false},
{position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N', disabled: false},
{position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O', disabled: true}, // should be hidden.
{position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F', disabled: true}, // should be hidden.
{position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne', disabled: true}, // should be hidden.
];
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ["position", "name", "weight", "symbol"];
dataSource = new MatTableDataSource(ELEMENT_DATA);
@ViewChild(MatPaginator) paginator!: MatPaginator;
ngOnInit(): void {
// This does not run in case filter is empty.
this.dataSource.filterPredicate = (
data: PeriodicElement,
filter: string
) => {
if (data.disabled) {
return false;
}
if (data.name.toLowerCase().indexOf(filter) > -1) {
return true;
}
return false;
};
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
I would like to hide rows which have disabled:true
(position 8, 9, 10 in the example above).
In my previous post, I first tried to set filterPredicate
. But this does not work in case filter string is empty. So I set [hidden]
parameter in html as below.
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [hidden]="row.disabled == true"></tr>
This looks fine, but I have a problem.
When the table is shown with paginator, the paginator's row count does not match dispalyed rows count.
This is Stackblitz sample. 7 rows are shown, but paginator's row count are 10.
I guess everything will be good if filterPredicate
can be applied with empty filter string.
Do I have a way for filterPredicate
to work even for empty string? Or do I have another solutions for this problem?
I found a strange solution to this.
Knowing that datasource.filterPredicate
is triggered only when dataSource.filter
is not empty set the dataSource.filter
to any string, say 'dummy' and then inside the datasource.filterPredicate
implement any logic.
let filterValue: String
ngOnInit(): void {
// This does not run in case filter is empty.
this.dataSource.filterPredicate = (
data: PeriodicElement
) => {
if (data.disabled) {
return false;
}
if (data.name.toLowerCase().indexOf(this.filterValue) > -1) {
return true;
}
return false;
};
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
}
applyFilter(event: Event) {
this.dataSource.filter = this.filterValue || "dummy";
}
}
letting filterValue
bind to your textelement
<input matInput [(ngModel)]="filterValue" (keyup)="applyFilter($event)" placeholder="Ex. ium" #input>
inside the applyFilter
doesn't mind at all the filter
parameter, so some code is unnecessary
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With