Filtering specific column in Angular Material table in angular 5 [duplicate]
Working filters on each column, demo link Stackblitz.
To filter specific column in mat-table, add a search field for the column as below;
<mat-form-field class="filter" floatLabel="never">
<mat-label>Search</mat-label>
<input matInput [formControl]="nameFilter">
</mat-form-field>
And we connect the inputs to FormControls from the ReactiveFormsModule.
filterValues = {
name: '',
id: '',
colour: '',
pet: ''
};
And we will watch the value of the filter inputs and modify this filter object and the data source’s filter property when they change. We must assign the stringified version of the filter object to the data source’s filter property
ngOnInit() {
this.nameFilter.valueChanges
.subscribe(
name => {
this.filterValues.name = name;
this.dataSource.filter = JSON.stringify(this.filterValues);
}
)
this.idFilter.valueChanges
.subscribe(
id => {
this.filterValues.id = id;
this.dataSource.filter = JSON.stringify(this.filterValues);
}
)
this.colourFilter.valueChanges
.subscribe(
colour => {
this.filterValues.colour = colour;
this.dataSource.filter = JSON.stringify(this.filterValues);
}
)
this.petFilter.valueChanges
.subscribe(
pet => {
this.filterValues.pet = pet;
this.dataSource.filter = JSON.stringify(this.filterValues);
}
)
}
We have to change the data source’s filterPredicate to tell it how to interpret the filter information.
constructor() {
this.dataSource.data = this.people;
this.dataSource.filterPredicate = this.tableFilter();
}
tableFilter(): (data: any, filter: string) => boolean {
let filterFunction = function(data, filter): boolean {
let searchTerms = JSON.parse(filter);
return data.name.toLowerCase().indexOf(searchTerms.name) !== -1
&& data.id.toString().toLowerCase().indexOf(searchTerms.id) !== -1
&& data.colour.toLowerCase().indexOf(searchTerms.colour) !== -1
&& data.pet.toLowerCase().indexOf(searchTerms.pet) !== -1;
}
return filterFunction;
}
I managed to do like this:
this.dataSource.filterPredicate = (data, filter) =>
(data.name.indexOf(filter) !== -1 ||
data.id.indexOf(filter) !== -1 );
}
Just declare a function with the following declaration in your component and then assign it to DataSource.filterPredicate. To use the filter just assign a string to DataSource.filter property.
customFilter(Data: T, Filter: string): boolean {
return <true if Data matches filter>
}
You can get to filter by a dynamic column, as in no hardcoded column name, doing the following:
// On input focus: setup filterPredicate to only filter by input column
setupFilter(column: string) {
this.dataSource.filterPredicate = (d: TableDataSourceType, filter: string) => {
const textToSearch = d[column] && d[column].toLowerCase() || '';
return textToSearch.indexOf(filter) !== -1;
};
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
In the template you can have something like this:
<ng-container matColumnDef="item-filter">
<th mat-header-cell *matHeaderCellDef>
<input (keyup)="applyFilter($event.target.value)" (focus)="setupFilter('name')" />
</th>
</ng-container>
Or a more complex example, dynamically create a header row with per-column filtering:
<table mat-table [dataSource]="dataSource">
<ng-container *ngFor="let filterCol of ['names', 'age', 'address']">
<ng-container matColumnDef="filterCol">
<th mat-header-cell *matHeaderCellDef>
<input (keyup)="applyFilter($event.target.value)" (focus)="setupFilter(filterCol)"/>
</th>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>
</table>
Be aware that you cannot have multiple header rows with the same keys, so this will not work:
<tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>
<tr mat-header-row *matHeaderRowDef="['names', 'age', 'address']"></tr>