Skip to content

Commit

Permalink
feat(filters): add setValues() optional flag to trigger query (#1574)
Browse files Browse the repository at this point in the history
* feat(filters): add optional arg to `setValues()` to trigger query
  • Loading branch information
ghiscoding committed Jun 14, 2024
1 parent 55d77d0 commit 025888d
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 59 deletions.
15 changes: 15 additions & 0 deletions packages/common/src/filters/__tests__/autocompleterFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,21 @@ describe('AutocompleterFilter', () => {
expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['abc'], shouldTriggerQuery: true });
});

it('should be able to call "setValues" and call an event trigger', () => {
mockColumn.filter.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
mockColumn.filter.filterOptions = { triggerOnEveryKeyStroke: true };
gridOptionMock.enableFilterTrimWhiteSpace = false;
mockColumn.filter.enableTrimWhiteSpace = true;
const spyCallback = jest.spyOn(filterArguments, 'callback');

filter.init(filterArguments);
filter.setValues('xyz', 'NE', true);
const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;

expect(filterElm).toBeTruthy();
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'NE', searchTerms: ['xyz'], shouldTriggerQuery: true });
});

it('should trigger the callback method when user types something in the input and triggerOnEveryKeyStroke is enabled', () => {
mockColumn.filter.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
mockColumn.filter.filterOptions = { triggerOnEveryKeyStroke: true };
Expand Down
12 changes: 12 additions & 0 deletions packages/common/src/filters/__tests__/compoundDateFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,18 @@ describe('CompoundDateFilter', () => {
expect(filterOperatorElm.value).toBe('>=');
});

it('should be able to call "setValues" and call an event trigger', () => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
const mockDate = '2001-01-02T16:02:02.239Z';
filter.init(filterArguments);
filter.setValues([mockDate], '>=', true);
const filterOperatorElm = divContainer.querySelector('.input-group-prepend.operator select') as HTMLInputElement;

expect(filter.currentDateOrDates).toEqual(mockDate);
expect(filterOperatorElm.value).toBe('>=');
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '>=', searchTerms: [mockDate], shouldTriggerQuery: true });
});

it('should trigger input change event and expect the callback to be called with the date provided in the input', () => {
mockColumn.filter!.operator = '>';
const spyCallback = jest.spyOn(filterArguments, 'callback');
Expand Down
10 changes: 10 additions & 0 deletions packages/common/src/filters/__tests__/compoundSliderFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ describe('CompoundSliderFilter', () => {
expect(filledInputElm).toBeFalsy();
});

it('should be able to call "setValues" and call an event trigger', () => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
filter.init(filterArguments);
filter.setValues(9, '>=', true);
let filledInputElm = divContainer.querySelector('.search-filter.filter-duration.filled') as HTMLInputElement;

expect(filledInputElm).toBeTruthy();
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '>=', searchTerms: [9], shouldTriggerQuery: true });
});

it('should create the input filter with default search terms range when passed as a filter argument', () => {
const filterArgs = { ...filterArguments, operator: '<=', searchTerms: [3], grid: gridStub } as FilterArguments;

Expand Down
10 changes: 10 additions & 0 deletions packages/common/src/filters/__tests__/inputFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ describe('InputFilter', () => {
expect(filledInputElm).toBeFalsy();
});

it('should be able to call "setValues" and call an event trigger', () => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
filter.init(filterArguments);
filter.setValues('9', '>', true);
let filledInputElm = divContainer.querySelector('.search-filter.filter-duration.filled') as HTMLInputElement;

expect(filledInputElm).toBeTruthy();
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: '>', searchTerms: ['>9'], shouldTriggerQuery: true });
});

it('should call "setValues" and include an operator and expect the operator to show up in the output search string shown in the filter input text value', () => {
filter.init(filterArguments);

Expand Down
13 changes: 13 additions & 0 deletions packages/common/src/filters/__tests__/selectFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ describe('SelectFilter', () => {

it('should provide boolean values and expect "getValues" to be converted to string', () => {
mockColumn.filter!.collection = [{ value: true, label: 'True' }, { value: false, label: 'False' }];

filter.init(filterArguments);
filter.setValues([false]);
const values = filter.getValues();
Expand All @@ -285,6 +286,18 @@ describe('SelectFilter', () => {
expect(values.length).toBe(1);
});

it('should be able to call "setValues" and call an event trigger', () => {
const spyCallback = jest.spyOn(filterArguments, 'callback');
mockColumn.filter!.collection = [{ value: true, label: 'True' }, { value: false, label: 'False' }];

filter.init(filterArguments);
filter.setValues([false], 'NE', true);
const values = filter.getValues();

expect(values).toEqual(['false']);
expect(spyCallback).toHaveBeenCalledWith(undefined, { columnDef: mockColumn, operator: 'NE', searchTerms: ['false'], shouldTriggerQuery: true });
});

it('should have empty array returned from "getValues" when nothing is set', () => {
mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
filter.init(filterArguments);
Expand Down
34 changes: 20 additions & 14 deletions packages/common/src/filters/autocompleterFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ export class AutocompleterFilter<T extends AutocompleteItem = any> implements Fi
this.searchTerms = [];
this._filterElm.value = '';
this._filterElm.dispatchEvent(new CustomEvent('input'));
this._filterElm.classList.remove('filled');
this.updateFilterStyle(false);
}
}

Expand All @@ -249,21 +249,24 @@ export class AutocompleterFilter<T extends AutocompleteItem = any> implements Fi
}

getValues(): string {
return this._filterElm?.value;
return this._filterElm?.value || '';
}

/** Set value(s) on the DOM element */
setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString): void {
setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString, triggerChange = false): void {
if (values && this._filterElm) {
this._filterElm.value = values as string;
}

// add/remove "filled" class name
const classCmd = this.getValues() !== '' ? 'add' : 'remove';
this._filterElm?.classList[classCmd]('filled');
this.updateFilterStyle(this.getValues() !== '');

// set the operator when defined
this.operator = operator || this.defaultOperator;

if (triggerChange) {
this.callback(undefined, { columnDef: this.columnDef, operator: this.operator, searchTerms: [this.getValues()], shouldTriggerQuery: true });
}
}

//
Expand Down Expand Up @@ -516,8 +519,7 @@ export class AutocompleterFilter<T extends AutocompleteItem = any> implements Fi
itemValue = this.trimWhitespaceWhenEnabled(itemValue);

// add/remove "filled" class name
const classCmd = itemValue === '' ? 'remove' : 'add';
this._filterElm?.classList[classCmd]('filled');
this.updateFilterStyle(itemValue !== '');

this.setValues(itemLabel);
this.callback(event, { columnDef: this.columnDef, operator: this.operator, searchTerms: [itemValue], shouldTriggerQuery: this._shouldTriggerQuery });
Expand Down Expand Up @@ -545,13 +547,7 @@ export class AutocompleterFilter<T extends AutocompleteItem = any> implements Fi
callbackArgs.searchTerms = [value];
}

if (value !== '') {
this.isItemSelected = true;
this._filterElm?.classList.add('filled');
} else {
this.isItemSelected = false;
this._filterElm?.classList.remove('filled');
}
this.updateFilterStyle(value !== '');
this.callback(e, callbackArgs);
}

Expand Down Expand Up @@ -605,4 +601,14 @@ export class AutocompleterFilter<T extends AutocompleteItem = any> implements Fi
}
return outputValue;
}

/** add/remove "filled" CSS class */
protected updateFilterStyle(isFilled: boolean): void {
this.isItemSelected = isFilled;
if (isFilled) {
this._filterElm.classList.add('filled');
} else {
this._filterElm.classList.remove('filled');
}
}
}
39 changes: 25 additions & 14 deletions packages/common/src/filters/dateFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ export class DateFilter implements Filter {
this._filterElm = this.createDomFilterElement(searchValues);

// if there's a search term, we will add the "filled" class for styling purposes
if (this.searchTerms.length) {
this._filterElm.classList.add('filled');
}
this.updateFilterStyle(this.searchTerms.length > 0);

// step 3, subscribe to the keyup event and run the callback when that happens
// also add/remove "filled" class for styling purposes
Expand Down Expand Up @@ -173,7 +171,7 @@ export class DateFilter implements Filter {
}
}
this.onTriggerEvent(new Event('keyup'));
this._filterElm.classList.remove('filled');
this.updateFilterStyle(false);
}

/** Destroy the filter */
Expand Down Expand Up @@ -207,7 +205,7 @@ export class DateFilter implements Filter {
* Set value(s) on the DOM element
* @params searchTerms
*/
setValues(values?: SearchTerm[] | SearchTerm, operator?: OperatorType | OperatorString): void {
setValues(values?: SearchTerm[] | SearchTerm, operator?: OperatorType | OperatorString, triggerChange = false): void {
let pickerValues: any | any[];

if (this.inputFilterType === 'compound') {
Expand All @@ -227,18 +225,21 @@ export class DateFilter implements Filter {
}

const currentValueOrValues = this.getValues() || [];
if (this.getValues() || (Array.isArray(currentValueOrValues) && currentValueOrValues.length > 0 && values)) {
this._filterElm.classList.add('filled');
} else {
this._filterElm.classList.remove('filled');
}
const searchTerms = Array.isArray(currentValueOrValues) ? currentValueOrValues : [currentValueOrValues];

// set the operator when defined
this.updateFilterStyle(searchTerms.length > 0);

// set the operator when defined
this.operator = operator || this.defaultOperator;
if (operator && this._selectOperatorElm) {
const operatorShorthand = mapOperatorToShorthandDesignation(this.operator);
this._selectOperatorElm.value = operatorShorthand;
}

if (triggerChange) {
this.callback(undefined, { columnDef: this.columnDef, searchTerms, operator: this.operator, shouldTriggerQuery: true });
}
}

//
Expand Down Expand Up @@ -486,14 +487,15 @@ export class DateFilter implements Filter {
protected onTriggerEvent(e: Event | undefined): void {
if (this._clearFilterTriggered) {
this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
this._filterElm.classList.remove('filled');
this.updateFilterStyle(false);
} else {
if (this.inputFilterType === 'range') {
(this._currentDateStrings) ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled');
this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentDateStrings ? this._currentDateStrings : [this._currentValue as string]), operator: this.operator || '', shouldTriggerQuery: this._shouldTriggerQuery });
const searchTerms = (this._currentDateStrings ? this._currentDateStrings : [this._currentValue as string]);
this.updateFilterStyle(searchTerms.length > 0);
this.callback(e, { columnDef: this.columnDef, searchTerms, operator: this.operator || '', shouldTriggerQuery: this._shouldTriggerQuery });
} else if (this.inputFilterType === 'compound' && this._selectOperatorElm) {
const selectedOperator = this._selectOperatorElm.value as OperatorString;
this._currentValue ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled');
this.updateFilterStyle(!!this._currentValue);

// when changing compound operator, we don't want to trigger the filter callback unless the date input is also provided
const skipNullInput = this.columnFilter.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput ?? this.gridOptions.skipCompoundOperatorFilterWithNullInput === undefined;
Expand All @@ -510,4 +512,13 @@ export class DateFilter implements Filter {
this._shouldTriggerQuery = true;
this._lastSearchValue = this._currentValue;
}

/** add/remove "filled" CSS class */
protected updateFilterStyle(isFilled: boolean): void {
if (isFilled) {
this._filterElm.classList.add('filled');
} else {
this._filterElm.classList.remove('filled');
}
}
}
37 changes: 22 additions & 15 deletions packages/common/src/filters/inputFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,10 @@ export class InputFilter implements Filter {
this.searchTerms = [];
this._filterInputElm.value = '';
this._currentValue = undefined;
this.updateFilterStyle(false);
if (this.inputFilterType === 'compound' && this._selectOperatorElm) {
this._selectOperatorElm.selectedIndex = 0;
this._filterContainerElm.classList.remove('filled');
}
this._filterInputElm.classList.remove('filled');
this.onTriggerEvent(undefined, true);
}
}
Expand All @@ -143,7 +142,7 @@ export class InputFilter implements Filter {
}

/** Set value(s) on the DOM element */
setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString): void {
setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString, triggerChange = false): void {
const searchValues = Array.isArray(values) ? values : [values];
let newInputValue: SearchTerm = '';
for (const value of searchValues) {
Expand All @@ -156,20 +155,19 @@ export class InputFilter implements Filter {
this._currentValue = this._filterInputElm.value;
}

if (this.getValues() !== '') {
this._filterContainerElm.classList.add('filled');
this._filterInputElm.classList.add('filled');
} else {
this._filterContainerElm.classList.remove('filled');
this._filterInputElm.classList.remove('filled');
}
// update "filled" CSS class
this.updateFilterStyle(this.getValues() !== '');

// set the operator when defined
this.operator = operator || this.defaultOperator;
if (operator && this._selectOperatorElm) {
const operatorShorthand = mapOperatorToShorthandDesignation(this.operator);
this._selectOperatorElm.value = operatorShorthand;
}

if (triggerChange) {
this.onTriggerEvent(undefined, false);
}
}

//
Expand Down Expand Up @@ -273,9 +271,7 @@ export class InputFilter implements Filter {
});

// if there's a search term, we will add the "filled" class for styling purposes
if (searchTerm) {
this._filterInputElm.classList.add('filled');
}
this.updateFilterStyle(!!searchTerm);
if (searchTerm !== undefined) {
this._currentValue = searchVal;
}
Expand Down Expand Up @@ -318,7 +314,7 @@ export class InputFilter implements Filter {
protected onTriggerEvent(event?: MouseEvent | KeyboardEvent, isClearFilterEvent = false): void {
if (isClearFilterEvent) {
this.callback(event, { columnDef: this.columnDef, clearFilterTriggered: isClearFilterEvent, shouldTriggerQuery: this._shouldTriggerQuery });
this._filterContainerElm.classList.remove('filled');
this.updateFilterStyle(false);
} else {
const eventType = event?.type ?? '';
const selectedOperator = (this._selectOperatorElm?.value ?? this.operator) as OperatorString;
Expand All @@ -332,7 +328,7 @@ export class InputFilter implements Filter {
this._currentValue = value;
}

value === '' ? this._filterContainerElm.classList.remove('filled') : this._filterContainerElm.classList.add('filled');
this.updateFilterStyle(value !== '');
const callbackArgs = { columnDef: this.columnDef, operator: selectedOperator, searchTerms: (value ? [value] : null), shouldTriggerQuery: this._shouldTriggerQuery };
const typingDelay = (eventType === 'keyup' && (event as KeyboardEvent)?.key !== 'Enter') ? this._debounceTypingDelay : 0;

Expand All @@ -353,4 +349,15 @@ export class InputFilter implements Filter {
// reset both flags for next use
this._shouldTriggerQuery = true;
}

/** add/remove "filled" CSS class */
protected updateFilterStyle(isFilled: boolean): void {
if (isFilled) {
this._filterContainerElm?.classList.add('filled');
this._filterInputElm.classList.add('filled');
} else {
this._filterContainerElm?.classList.remove('filled');
this._filterInputElm.classList.remove('filled');
}
}
}
Loading

0 comments on commit 025888d

Please sign in to comment.