From dfdc2832b941507eabc801a8d4e12d1e1b9f0b4c Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Thu, 26 Oct 2017 13:44:21 -0700 Subject: [PATCH 1/4] fix(table): broaden abstraction for filtering --- src/demo-app/table/table-demo.ts | 3 ++- src/lib/table/table-data-source.ts | 34 ++++++++++++++++++++---------- src/lib/table/table.spec.ts | 21 ++++++++++-------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/demo-app/table/table-demo.ts b/src/demo-app/table/table-demo.ts index efecfc9e6995..fa2bebcecbdb 100644 --- a/src/demo-app/table/table-demo.ts +++ b/src/demo-app/table/table-demo.ts @@ -60,7 +60,8 @@ export class TableDemo { default: return ''; } }; - this.matTableDataSource.filterTermAccessor = (data: UserData) => data.name; + this.matTableDataSource.filterMatcher = + (data: UserData, filter: string) => data.name.indexOf(filter) != -1; this.filter.valueChanges.subscribe(filter => this.matTableDataSource!.filter = filter); } diff --git a/src/lib/table/table-data-source.ts b/src/lib/table/table-data-source.ts index 14852a5f570f..2d16906da089 100644 --- a/src/lib/table/table-data-source.ts +++ b/src/lib/table/table-data-source.ts @@ -43,8 +43,11 @@ export class MatTableDataSource implements DataSource { get data() { return this._data.value; } /** - * 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. + * Filter term that should be used to filter out objects from the data array. Will be transformed + * by the filterTransformer function, which by default will transform the filter into lowercase + * and remove surrounding whitespace. To override this behavior, provide a custom function on the + * filterTransformer. To override how data objects are converted to strings to match again, + * provide a custom function on filterTermAccessor. */ set filter(filter: string) { this._filter.next(filter); } get filter(): string { return this._filter.value; } @@ -91,14 +94,24 @@ export class MatTableDataSource implements DataSource { } /** - * 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 + * removed 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 => { + filterMatcher: ((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[] = []) { @@ -141,9 +154,8 @@ export class MatTableDataSource implements DataSource { // 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.filterMatcher(obj, this.filter)); if (this.paginator) { this._updatePaginator(filteredData.length); } diff --git a/src/lib/table/table.spec.ts b/src/lib/table/table.spec.ts index 39949cf92b19..69c783e1c1d6 100644 --- a/src/lib/table/table.spec.ts +++ b/src/lib/table/table.spec.ts @@ -98,7 +98,7 @@ describe('MatTable', () => { ]); }); - it('should be able to filter the table contents', fakeAsync(() => { + fit('should be able to filter the table contents', fakeAsync(() => { // Change filter to a_1, should match one row dataSource.filter = 'a_1'; fixture.detectChanges(); @@ -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'], @@ -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.filterMatcher = (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(); From 649538df1263455a0886a11b5cfdf865fafea4cf Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Thu, 26 Oct 2017 13:52:05 -0700 Subject: [PATCH 2/4] cleanup --- src/lib/table/table-data-source.ts | 7 ++----- src/lib/table/table.spec.ts | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/table/table-data-source.ts b/src/lib/table/table-data-source.ts index 2d16906da089..061ee6a87e2b 100644 --- a/src/lib/table/table-data-source.ts +++ b/src/lib/table/table-data-source.ts @@ -43,11 +43,8 @@ export class MatTableDataSource implements DataSource { get data() { return this._data.value; } /** - * Filter term that should be used to filter out objects from the data array. Will be transformed - * by the filterTransformer function, which by default will transform the filter into lowercase - * and remove surrounding whitespace. To override this behavior, provide a custom function on the - * filterTransformer. To override how data objects are converted to strings to match again, - * provide a custom function on filterTermAccessor. + * Filter term that should be used to filter out objects from the data array. To override how + * data objects match to this filter string, provide a custom function for filterMatcher. */ set filter(filter: string) { this._filter.next(filter); } get filter(): string { return this._filter.value; } diff --git a/src/lib/table/table.spec.ts b/src/lib/table/table.spec.ts index 69c783e1c1d6..e0b90a89d309 100644 --- a/src/lib/table/table.spec.ts +++ b/src/lib/table/table.spec.ts @@ -98,7 +98,7 @@ describe('MatTable', () => { ]); }); - fit('should be able to filter the table contents', fakeAsync(() => { + it('should be able to filter the table contents', fakeAsync(() => { // Change filter to a_1, should match one row dataSource.filter = 'a_1'; fixture.detectChanges(); From a1f9fa9704c64f886c3fe1c0a519d30511d79ab6 Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Thu, 26 Oct 2017 17:10:20 -0700 Subject: [PATCH 3/4] rename filter function --- src/demo-app/table/table-demo.ts | 2 +- src/lib/table/table-data-source.ts | 6 +++--- src/lib/table/table.spec.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/demo-app/table/table-demo.ts b/src/demo-app/table/table-demo.ts index fa2bebcecbdb..691190cb73dc 100644 --- a/src/demo-app/table/table-demo.ts +++ b/src/demo-app/table/table-demo.ts @@ -60,7 +60,7 @@ export class TableDemo { default: return ''; } }; - this.matTableDataSource.filterMatcher = + this.matTableDataSource.filterPredicate = (data: UserData, filter: string) => data.name.indexOf(filter) != -1; this.filter.valueChanges.subscribe(filter => this.matTableDataSource!.filter = filter); } diff --git a/src/lib/table/table-data-source.ts b/src/lib/table/table-data-source.ts index 061ee6a87e2b..ff463cac5adb 100644 --- a/src/lib/table/table-data-source.ts +++ b/src/lib/table/table-data-source.ts @@ -44,7 +44,7 @@ export class MatTableDataSource implements DataSource { /** * Filter term that should be used to filter out objects from the data array. To override how - * data objects match to this filter string, provide a custom function for filterMatcher. + * 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; } @@ -100,7 +100,7 @@ export class MatTableDataSource implements DataSource { * @param filter Filter string that has been set on the data source. * @returns Whether the filter matches against the data */ - filterMatcher: ((data: T, filter: string) => boolean) = (data: T, filter: string): boolean => { + 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]; const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase(); @@ -152,7 +152,7 @@ export class MatTableDataSource implements DataSource { // 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 => this.filterMatcher(obj, this.filter)); + !this.filter ? data : data.filter(obj => this.filterPredicate(obj, this.filter)); if (this.paginator) { this._updatePaginator(filteredData.length); } diff --git a/src/lib/table/table.spec.ts b/src/lib/table/table.spec.ts index e0b90a89d309..eac0a880fff9 100644 --- a/src/lib/table/table.spec.ts +++ b/src/lib/table/table.spec.ts @@ -128,7 +128,7 @@ describe('MatTable', () => { ]); // Change filter function and filter, should match to rows with zebra. - dataSource.filterMatcher = (data, filter) => { + dataSource.filterPredicate = (data, filter) => { let dataStr; switch (data.a) { case 'a_1': dataStr = 'elephant'; break; From 2e4835153aa0bcf8e8e034b399c7a6c7d17647bc Mon Sep 17 00:00:00 2001 From: Andrew Seguin Date: Fri, 27 Oct 2017 15:50:51 -0700 Subject: [PATCH 4/4] fix wording --- src/lib/table/table-data-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/table/table-data-source.ts b/src/lib/table/table-data-source.ts index ff463cac5adb..eb215d05fc80 100644 --- a/src/lib/table/table-data-source.ts +++ b/src/lib/table/table-data-source.ts @@ -94,7 +94,7 @@ export class MatTableDataSource implements DataSource { * 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 - * removed and the match is case-insensitive. May be overriden for a custom implementation of + * 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.