I have angular 4 project with material 2, I want to filter the data in MatTable. DataSource filter is working fine when we filter data on field which are not nested.
<This is a very generic solution and will work for sure. It does not depends on the structure of json, be it simple or nested, this solution works for all.
this.dataSource.filterPredicate = (data: any, filter) => {
const dataStr =JSON.stringify(data).toLowerCase();
return dataStr.indexOf(filter) != -1;
}
Here is a solution that incorporates recursion so you don't have to hard code each nested object or their key/value pairs.
this.dataSource.filterPredicate = (data, filter: string) => {
const accumulator = (currentTerm, key) => {
return this.nestedFilterCheck(currentTerm, data, key);
};
const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
// Transform the filter by converting it to lowercase and removing whitespace.
const transformedFilter = filter.trim().toLowerCase();
return dataStr.indexOf(transformedFilter) !== -1;
};
And the nestedFilterCheck
nestedFilterCheck(search, data, key) {
if (typeof data[key] === 'object') {
for (const k in data[key]) {
if (data[key][k] !== null) {
search = this.nestedFilterCheck(search, data[key], k);
}
}
} else {
search += data[key];
}
return search;
}
Thanks to @Sagar Kharche for the filterPredicate
override.
DataSource has filterPredicate()
method that needs to override in our application as follows. Add this code in your component after data source initialization.
this.dataSource.filterPredicate = (data, filter: string) => {
const accumulator = (currentTerm, key) => {
return key === 'orderInfo' ? currentTerm + data.orderInfo.type : currentTerm + data[key];
};
const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
// Transform the filter by converting it to lowercase and removing whitespace.
const transformedFilter = filter.trim().toLowerCase();
return dataStr.indexOf(transformedFilter) !== -1;
};