Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(table): broaden abstraction for filtering #8059

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/demo-app/table/table-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export class TableDemo {
default: return '';
}
};
this.matTableDataSource.filterTermAccessor = (data: UserData) => data.name;
this.matTableDataSource.filterPredicate =
(data: UserData, filter: string) => data.name.indexOf(filter) != -1;
this.filter.valueChanges.subscribe(filter => this.matTableDataSource!.filter = filter);
}

Expand Down
29 changes: 19 additions & 10 deletions src/lib/table/table-data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class MatTableDataSource<T> implements DataSource<T> {

/**
* Filter term that should be used to filter out objects from the data array. To override how
* the filter matches data objects, provide a custom function on filterTermAccessor.
* data objects match to this filter string, provide a custom function for filterPredicate.
*/
set filter(filter: string) { this._filter.next(filter); }
get filter(): string { return this._filter.value; }
Expand Down Expand Up @@ -91,14 +91,24 @@ export class MatTableDataSource<T> implements DataSource<T> {
}

/**
* Transforms data objects into a filter term that will be used to check against the filter if
* a filter is set. By default, the function will iterate over the values of the data object
* and convert them to a lowercase string.
* @param data Data object to convert to a string that checked for containing the filter term.
* Checks if a data object matches the data source's filter string. By default, each data object
* is converted to a string of its properties and returns true if the filter has
* at least one occurrence in that string. By default, the filter string has its whitespace
* trimmed and the match is case-insensitive. May be overriden for a custom implementation of
* filter matching.
* @param data Data object used to check against the filter.
* @param filter Filter string that has been set on the data source.
* @returns Whether the filter matches against the data
*/
filterTermAccessor: ((data: T) => string) = (data: T): string => {
filterPredicate: ((data: T, filter: string) => boolean) = (data: T, filter: string): boolean => {
// Transform the data into a lowercase string of all property values.
const accumulator = (currentTerm, key) => currentTerm + data[key];
return Object.keys(data).reduce(accumulator, '').toLowerCase();
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;
}

constructor(initialData: T[] = []) {
Expand Down Expand Up @@ -141,9 +151,8 @@ export class MatTableDataSource<T> implements DataSource<T> {
// If there is a filter string, filter out data that does not contain it.
// Each data object is converted to a string using the function defined by filterTermAccessor.
// May be overriden for customization.
const filteredData = !this.filter ? data : data.filter(obj => {
return this.filterTermAccessor(obj).indexOf(this.filter) != -1;
});
const filteredData =
!this.filter ? data : data.filter(obj => this.filterPredicate(obj, this.filter));

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

Expand Down
19 changes: 11 additions & 8 deletions src/lib/table/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ describe('MatTable', () => {
flushMicrotasks(); // Resolve promise that updates paginator's length
expect(dataSource.paginator!.length).toBe(1);

// Change filter to a_2, should match one row
dataSource.filter = 'a_2';
// Change filter to ' A_2 ', should match one row (ignores case and whitespace)
dataSource.filter = ' A_2 ';
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
Expand All @@ -127,14 +127,17 @@ describe('MatTable', () => {
['a_3', 'b_3', 'c_3'],
]);

// Change filter function and filter, should match to rows.
dataSource.filterTermAccessor = data => {
// Change filter function and filter, should match to rows with zebra.
dataSource.filterPredicate = (data, filter) => {
let dataStr;
switch (data.a) {
case 'a_1': return 'elephant';
case 'a_2': return 'zebra';
case 'a_3': return 'monkey';
default: return '';
case 'a_1': dataStr = 'elephant'; break;
case 'a_2': dataStr = 'zebra'; break;
case 'a_3': dataStr = 'monkey'; break;
default: dataStr = '';
}

return dataStr.indexOf(filter) != -1;
};
dataSource.filter = 'zebra';
fixture.detectChanges();
Expand Down