Skip to content

Commit

Permalink
fix(table): broaden abstraction for filtering (#8059)
Browse files Browse the repository at this point in the history
* fix(table): broaden abstraction for filtering

* cleanup

* rename filter function

* fix wording
  • Loading branch information
andrewseguin authored and mmalerba committed Oct 30, 2017
1 parent b2dd17a commit d47b37a
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 19 deletions.
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 @@ -145,9 +155,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

0 comments on commit d47b37a

Please sign in to comment.