From 3e8d2cbcea6181e3ce3157798f003a8479d11011 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Wed, 21 Apr 2021 10:47:37 -0400 Subject: [PATCH] feat(filters): option to add custom compound operator list --- .../__tests__/compoundDateFilter.spec.ts | 19 ++++++ .../__tests__/compoundInputFilter.spec.ts | 19 ++++++ .../__tests__/compoundSliderFilter.spec.ts | 19 ++++++ .../common/src/filters/compoundDateFilter.ts | 28 +++++---- .../common/src/filters/compoundInputFilter.ts | 60 ++++++++++--------- .../src/filters/compoundSliderFilter.ts | 29 +++++---- .../src/interfaces/columnFilter.interface.ts | 7 ++- packages/common/src/interfaces/index.ts | 1 + .../interfaces/operatorDetail.interface.ts | 7 +++ 9 files changed, 137 insertions(+), 52 deletions(-) create mode 100644 packages/common/src/interfaces/operatorDetail.interface.ts diff --git a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts index 6e718d9d6..8d9aa7c58 100644 --- a/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundDateFilter.spec.ts @@ -344,6 +344,25 @@ describe('CompoundDateFilter', () => { expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Not equal to'); }); + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['2000-01-01T05:00:00.000Z']; + mockColumn.filter.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.input-group-prepend.operator select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); + }); + describe('with French I18N translations', () => { beforeEach(() => { gridOptionMock.enableTranslate = true; diff --git a/packages/common/src/filters/__tests__/compoundInputFilter.spec.ts b/packages/common/src/filters/__tests__/compoundInputFilter.spec.ts index 2d4a64dce..85a4b494f 100644 --- a/packages/common/src/filters/__tests__/compoundInputFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundInputFilter.spec.ts @@ -320,6 +320,25 @@ describe('CompoundInputFilter', () => { expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false }); }); + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['xyz']; + mockColumn.filter.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); + }); + describe('with French I18N translations', () => { beforeEach(() => { gridOptionMock.enableTranslate = true; diff --git a/packages/common/src/filters/__tests__/compoundSliderFilter.spec.ts b/packages/common/src/filters/__tests__/compoundSliderFilter.spec.ts index 0bccfb525..b0ea0146b 100644 --- a/packages/common/src/filters/__tests__/compoundSliderFilter.spec.ts +++ b/packages/common/src/filters/__tests__/compoundSliderFilter.spec.ts @@ -239,6 +239,25 @@ describe('CompoundSliderFilter', () => { expect(removeExtraSpaces(filterOperatorElm[0][6].textContent!)).toBe('<> Not equal to'); }); + it('should have custom compound operator list showing up in the operator select dropdown options list', () => { + mockColumn.outputType = null as any; + filterArguments.searchTerms = ['9']; + mockColumn.filter.compoundOperatorList = [ + { operator: '', description: '' }, + { operator: '=', description: 'Equal to' }, + { operator: '<', description: 'Less than' }, + { operator: '>', description: 'Greater than' }, + ]; + + filter.init(filterArguments); + const filterOperatorElm = divContainer.querySelectorAll('.search-filter.filter-duration select'); + + expect(filterOperatorElm[0][0].title).toBe(''); + expect(removeExtraSpaces(filterOperatorElm[0][1].textContent!)).toBe('= Equal to'); + expect(removeExtraSpaces(filterOperatorElm[0][2].textContent!)).toBe('< Less than'); + expect(removeExtraSpaces(filterOperatorElm[0][3].textContent!)).toBe('> Greater than'); + }); + describe('with French I18N translations', () => { beforeEach(() => { gridOptionMock.enableTranslate = true; diff --git a/packages/common/src/filters/compoundDateFilter.ts b/packages/common/src/filters/compoundDateFilter.ts index 90dd6d090..f6f0223c5 100644 --- a/packages/common/src/filters/compoundDateFilter.ts +++ b/packages/common/src/filters/compoundDateFilter.ts @@ -12,6 +12,7 @@ import { FlatpickrOption, GridOption, Locale, + OperatorDetail, SlickGrid, } from '../interfaces/index'; import { FieldType, OperatorString, OperatorType, SearchTerm } from '../enums/index'; @@ -229,16 +230,21 @@ export class CompoundDateFilter implements Filter { return $filterInputElm; } - protected getOptionValues(): { operator: OperatorString, description: string }[] { - return [ - { operator: '', description: '' }, - { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + return [ + { operator: '', description: '' }, + { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + } } /** Get Locale, Translated or a Default Text if first two aren't detected */ @@ -259,7 +265,7 @@ export class CompoundDateFilter implements Filter { $($headerElm).empty(); // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = this.buildDatePickerInput(searchTerm); const $filterContainerElm = $(`
`); diff --git a/packages/common/src/filters/compoundInputFilter.ts b/packages/common/src/filters/compoundInputFilter.ts index 164ab8de5..71b0823b0 100644 --- a/packages/common/src/filters/compoundInputFilter.ts +++ b/packages/common/src/filters/compoundInputFilter.ts @@ -8,6 +8,7 @@ import { FilterCallback, GridOption, Locale, + OperatorDetail, SlickGrid, } from '../interfaces/index'; import { buildSelectOperatorHtmlString } from './filterUtilities'; @@ -158,35 +159,40 @@ export class CompoundInputFilter implements Filter { return ``; } - protected getOptionValues(): { operator: OperatorString, description: string }[] { + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { const type = (this.columnDef.type && this.columnDef.type) ? this.columnDef.type : FieldType.string; let optionValues = []; - switch (type) { - case FieldType.string: - case FieldType.text: - case FieldType.readonly: - case FieldType.password: - optionValues = [ - { operator: '' as OperatorString, description: this.getOutputText('CONTAINS', 'TEXT_CONTAINS', 'Contains') }, - { operator: '<>' as OperatorString, description: this.getOutputText('NOT_CONTAINS', 'TEXT_NOT_CONTAINS', 'Not Contains') }, - { operator: '=' as OperatorString, description: this.getOutputText('EQUALS', 'TEXT_EQUALS', 'Equals') }, - { operator: '!=' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') }, - { operator: 'a*' as OperatorString, description: this.getOutputText('STARTS_WITH', 'TEXT_STARTS_WITH', 'Starts with') }, - { operator: '*z' as OperatorString, description: this.getOutputText('ENDS_WITH', 'TEXT_ENDS_WITH', 'Ends with') }, - ]; - break; - default: - optionValues = [ - { operator: '' as OperatorString, description: '' }, - { operator: '=' as OperatorString, description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<' as OperatorString, description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=' as OperatorString, description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>' as OperatorString, description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=' as OperatorString, description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; - break; + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + switch (type) { + case FieldType.string: + case FieldType.text: + case FieldType.readonly: + case FieldType.password: + optionValues = [ + { operator: '' as OperatorString, description: this.getOutputText('CONTAINS', 'TEXT_CONTAINS', 'Contains') }, + { operator: '<>' as OperatorString, description: this.getOutputText('NOT_CONTAINS', 'TEXT_NOT_CONTAINS', 'Not Contains') }, + { operator: '=' as OperatorString, description: this.getOutputText('EQUALS', 'TEXT_EQUALS', 'Equals') }, + { operator: '!=' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') }, + { operator: 'a*' as OperatorString, description: this.getOutputText('STARTS_WITH', 'TEXT_STARTS_WITH', 'Starts with') }, + { operator: '*z' as OperatorString, description: this.getOutputText('ENDS_WITH', 'TEXT_ENDS_WITH', 'Ends with') }, + ]; + break; + default: + optionValues = [ + { operator: '' as OperatorString, description: '' }, + { operator: '=' as OperatorString, description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<' as OperatorString, description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=' as OperatorString, description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>' as OperatorString, description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=' as OperatorString, description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>' as OperatorString, description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + break; + } } return optionValues; @@ -210,7 +216,7 @@ export class CompoundInputFilter implements Filter { $($headerElm).empty(); // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = $(this.buildInputHtmlString()); const $filterContainerElm = $(`
`); diff --git a/packages/common/src/filters/compoundSliderFilter.ts b/packages/common/src/filters/compoundSliderFilter.ts index 4025b95e9..d4ddae836 100644 --- a/packages/common/src/filters/compoundSliderFilter.ts +++ b/packages/common/src/filters/compoundSliderFilter.ts @@ -6,6 +6,7 @@ import { FilterCallback, GridOption, Locale, + OperatorDetail, SlickGrid, } from '../interfaces/index'; import { Constants } from '../constants'; @@ -204,17 +205,21 @@ export class CompoundSliderFilter implements Filter { return `
${defaultValue}
`; } - /** Get the available operator option values */ - protected getOptionValues(): { operator: OperatorString, description: string }[] { - return [ - { operator: '', description: '' }, - { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, - { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, - { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, - { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, - { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, - { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } - ]; + /** Get the available operator option values to populate the operator select dropdown list */ + protected getOperatorOptionValues(): OperatorDetail[] { + if (this.columnFilter?.compoundOperatorList) { + return this.columnFilter.compoundOperatorList; + } else { + return [ + { operator: '', description: '' }, + { operator: '=', description: this.getOutputText('EQUAL_TO', 'TEXT_EQUAL_TO', 'Equal to') }, + { operator: '<', description: this.getOutputText('LESS_THAN', 'TEXT_LESS_THAN', 'Less than') }, + { operator: '<=', description: this.getOutputText('LESS_THAN_OR_EQUAL_TO', 'TEXT_LESS_THAN_OR_EQUAL_TO', 'Less than or equal to') }, + { operator: '>', description: this.getOutputText('GREATER_THAN', 'TEXT_GREATER_THAN', 'Greater than') }, + { operator: '>=', description: this.getOutputText('GREATER_THAN_OR_EQUAL_TO', 'TEXT_GREATER_THAN_OR_EQUAL_TO', 'Greater than or equal to') }, + { operator: '<>', description: this.getOutputText('NOT_EQUAL_TO', 'TEXT_NOT_EQUAL_TO', 'Not equal to') } + ]; + } } /** Get Locale, Translated or a Default Text if first two aren't detected */ @@ -246,7 +251,7 @@ export class CompoundSliderFilter implements Filter { this._currentValue = +searchTermInput; // create the DOM Select dropdown for the Operator - const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOptionValues()); + const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues()); this.$selectOperatorElm = $(selectOperatorHtmlString); this.$filterInputElm = $(this.buildTemplateHtmlString()); const $filterContainerElm = $(`
`); diff --git a/packages/common/src/interfaces/columnFilter.interface.ts b/packages/common/src/interfaces/columnFilter.interface.ts index ce714c0ab..fd683c803 100644 --- a/packages/common/src/interfaces/columnFilter.interface.ts +++ b/packages/common/src/interfaces/columnFilter.interface.ts @@ -1,4 +1,4 @@ -import { FieldType, OperatorString, OperatorType, } from '../enums/index'; +import { FieldType, OperatorString, OperatorType, SearchTerm, } from '../enums/index'; import { CollectionCustomStructure, CollectionFilterBy, @@ -7,8 +7,8 @@ import { Column, Filter, MultipleSelectOption, + OperatorDetail, } from './index'; -import { SearchTerm } from '../enums/searchTerm.type'; import { Observable, Subject } from '../services/rxjsFacade'; export interface ColumnFilter { @@ -30,6 +30,9 @@ export interface ColumnFilter { /** Column Definition */ columnDef?: Column; + /** Optional operator list to override the full list of Compound Operator select dropdown list. */ + compoundOperatorList?: OperatorDetail[]; + /** Custom Filter */ customFilter?: Filter; diff --git a/packages/common/src/interfaces/index.ts b/packages/common/src/interfaces/index.ts index f3dec471c..0f3461ba2 100644 --- a/packages/common/src/interfaces/index.ts +++ b/packages/common/src/interfaces/index.ts @@ -109,6 +109,7 @@ export * from './multiColumnSort.interface'; export * from './multipleSelectOption.interface'; export * from './onEventArgs.interface'; export * from './onValidationErrorResult.interface'; +export * from './operatorDetail.interface'; export * from './pagination.interface'; export * from './paginationChangedArgs.interface'; export * from './pagingInfo.interface'; diff --git a/packages/common/src/interfaces/operatorDetail.interface.ts b/packages/common/src/interfaces/operatorDetail.interface.ts new file mode 100644 index 000000000..5b1317feb --- /dev/null +++ b/packages/common/src/interfaces/operatorDetail.interface.ts @@ -0,0 +1,7 @@ +import { OperatorString, OperatorType } from '../enums/index'; + +/** Operator with its Description */ +export interface OperatorDetail { + operator: OperatorString | OperatorType; + description: string; +} \ No newline at end of file