Hi have a Data table with 4 cols- Name, Age, Marks, School. Now I want to apply filter for each of the columns. The filter works fine individually. But I am not able to combine the results of filter - example I am not able to filter out the Name which has marks > 90 and from 'abc' School.
I tried something like this, but it did not work.
applyFilter(filterValue: string) {
console.log("Filter is applied upon:",this.dataSource)
let initialDataSource = this.dataSource;
this.dataSource.filter = filterValue.trim().toLowerCase();
this.filteredDataSource = this.dataSource.filteredData
this.filterVal = this.dataSource.filter;
if(this.filterVal.length != 0){
this.dataSource = new MatTableDataSource(this.filteredDataSource);
this.dataSource.filter = filterValue.trim().toLowerCase();
}else{
this.dataSource = initialDataSource;
this.dataSource.filter = filterValue.trim().toLowerCase();
this.filteredDataSource = this.dataSource.filteredData
}
}
The above function does the filtering, but when I clear out the filter value, the table data does not change. Also it does not change when I delete a character.
Declare the TableFilter interface for convenience:
interface ITableFilter {
column: string;
value: any;
}
The filter predicate function is being called once per row(!) when filtering is applied: if the predicate returns true, the current row will be included in filtered results. So we'll iterate over our filters array and return false if there's a mismatch in one of the columns.
Replace your dataSource filterPredicate with the following custom one:
setDataSource() {
this.dataSource = new MatTableDataSource(this.yourData);
this.dataSource.filterPredicate = this.customFilterPredicate;
}
customFilterPredicate(data: any, filters: ITableFilter[]): boolean {
for (let i = 0; i < filters.length; i++) {
const fitsThisFilter = data[filters[i].column].includes(filters[i].value);
if (!fitsThisFilter) {
return false;
}
}
return true;
}
Afterwards you may apply your filter like that:
// implement some relevant logic to build the filters array
const filter: ITableFilter | any = [{column: 'name', value: 'foo'}, {column: 'description', value: 'bar'}];
// this is how you apply a filter
this.dataSource.filter = filter;
It's a little bit hackish that we need to set filters as 'any'; but the filter function expects a string, and I found no other way to get around it.
Althoug the answer from grreeenn is perfectly fine, I wasn't able to combine multiple filter values with this approach. This is what I came up with:
The filters array would consist of multiple objects
const filters = [{key: name, filterValue: 'Mark'}, {key: score, filterValue: 1}]
To make the filterPredicate accept the list you can stringify the array with
JSON.stringify(filters)
I changed the filterPredicate method a little to work with multiple values at once
customFilterPredicate(data: any, filters: string): boolean {
let match = true;
const filtersList = JSON.parse(filters)
filtersList.forEach(filterObj => {
match = match && data[filterObj.key].toLocaleLowerCase().indexOf(filterObj.filterValue.toLocaleLowerCase()) !== -1;
});
return match;
};
So the filter would only return true if all values are matched, otherwise it returns false.
You can do so by replacing the filterPredicate function with your own filter function and passing multiple values (as an object) to the filter.
Example code:
this.timeSlotDataSource.filterPredicate = (data: any, filterObjString: string) => {
const filterObj = JSON.parse(filterObjString);
const filterValue1 = filterObj.filterValue1;
const filterValue2 = filterObj.filterValue2;
const filterValue3 = filterObj.filterValue3;
let available = false;
// You may add additional logic here if needed
if('your own logic')
available = true;
else
return false;
return available &&
( data.slotName.toLowerCase().indexOf(filterValue1) !== -1 ||
data.slotInfo.toLowerCase().indexOf(filterValue2) !== -1 ||
data.slotTime.toLowerCase().indexOf(filterValue3) !== -1);
}
filter(){
const filterObj = {
filterValue1: this.filterValue1,
filterValue2: this.filterValue2,
filterValue3: this.filterValue3,
};
this.timeSlotDataSource.filter = JSON.stringify(filterObj);
}
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