diff --git a/packages/common/src/filters/compoundDateFilter.ts b/packages/common/src/filters/compoundDateFilter.ts
index 31532d7f4..014bc6fd2 100644
--- a/packages/common/src/filters/compoundDateFilter.ts
+++ b/packages/common/src/filters/compoundDateFilter.ts
@@ -140,12 +140,8 @@ export class CompoundDateFilter implements Filter {
destroyObjectDomElementProps(this.flatInstance);
}
}
- if (this._filterElm) {
- this._filterElm.remove();
- }
- if (this._selectOperatorElm) {
- this._selectOperatorElm.remove();
- }
+ this._filterElm?.remove?.();
+ this._selectOperatorElm?.remove?.();
}
hide() {
@@ -225,14 +221,16 @@ export class CompoundDateFilter implements Filter {
};
// add the time picker when format is UTC (Z) or has the 'h' (meaning hours)
- if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().indexOf('h') > -1)) {
+ if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) {
pickerOptions.enableTime = true;
}
// merge options with optional user's custom options
this._flatpickrOptions = { ...pickerOptions, ...userFilterOptions };
- let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
- if (this.columnFilter && this.columnFilter.placeholder) {
+
+ // create the DOM element & add an ID and filter class
+ let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? '';
+ if (this.columnFilter?.placeholder) {
placeholder = this.columnFilter.placeholder;
}
diff --git a/packages/common/src/filters/compoundInputFilter.ts b/packages/common/src/filters/compoundInputFilter.ts
index 71b0823b0..668f18b39 100644
--- a/packages/common/src/filters/compoundInputFilter.ts
+++ b/packages/common/src/filters/compoundInputFilter.ts
@@ -11,18 +11,20 @@ import {
OperatorDetail,
SlickGrid,
} from '../interfaces/index';
-import { buildSelectOperatorHtmlString } from './filterUtilities';
-import { getTranslationPrefix, mapOperatorToShorthandDesignation } from '../services/utilities';
+import { buildSelectOperator } from './filterUtilities';
+import { emptyElement, getTranslationPrefix, mapOperatorToShorthandDesignation } from '../services/utilities';
+import { BindingEventService } from '../services/bindingEvent.service';
import { TranslaterService } from '../services/translater.service';
export class CompoundInputFilter implements Filter {
+ protected _bindEventService: BindingEventService;
protected _clearFilterTriggered = false;
protected _debounceTypingDelay = 0;
protected _shouldTriggerQuery = true;
protected _inputType = 'text';
- protected $filterElm: any;
- protected $filterInputElm: any;
- protected $selectOperatorElm: any;
+ protected _filterElm!: HTMLDivElement;
+ protected _filterInputElm!: HTMLInputElement;
+ protected _selectOperatorElm!: HTMLSelectElement;
protected _operator?: OperatorType | OperatorString;
grid!: SlickGrid;
searchTerms: SearchTerm[] = [];
@@ -30,16 +32,18 @@ export class CompoundInputFilter implements Filter {
callback!: FilterCallback;
timer?: NodeJS.Timeout;
- constructor(protected readonly translaterService: TranslaterService) { }
+ constructor(protected readonly translaterService: TranslaterService) {
+ this._bindEventService = new BindingEventService();
+ }
/** Getter for the Grid Options pulled through the Grid Object */
protected get gridOptions(): GridOption {
- return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
+ return this.grid?.getOptions?.() ?? {};
}
- /** Getter for the Filter Operator */
+ /** Getter for the Column Filter */
get columnFilter(): ColumnFilter {
- return this.columnDef && this.columnDef.filter || {};
+ return this.columnDef?.filter ?? {};
}
/** Getter to know what would be the default operator when none is specified */
@@ -83,7 +87,7 @@ export class CompoundInputFilter implements Filter {
this.grid = args.grid;
this.callback = args.callback;
this.columnDef = args.columnDef;
- this.operator = args.operator || '';
+ this.operator = args.operator as OperatorString;
this.searchTerms = (args.hasOwnProperty('searchTerms') ? args.searchTerms : []) || [];
// analyze if we have any keyboard debounce delay (do we wait for user to finish typing before querying)
@@ -96,25 +100,25 @@ export class CompoundInputFilter implements Filter {
// step 1, create the DOM Element of the filter which contain the compound Operator+Input
// and initialize it if searchTerm is filled
- this.$filterElm = this.createDomElement(searchTerm);
+ this._filterElm = this.createDomElement(searchTerm);
- // step 3, subscribe to the input change event and run the callback when that happens
+ // step 3, subscribe to the keyup event and run the callback when that happens
// also add/remove "filled" class for styling purposes
// we'll use all necessary events to cover the following (keyup, change, mousewheel & spinner)
- this.$filterInputElm.on('keyup blur change wheel', this.onTriggerEvent.bind(this));
- this.$selectOperatorElm.on('change', this.onTriggerEvent.bind(this));
+ this._bindEventService.bind(this._filterInputElm, ['keyup', 'blur', 'change', 'wheel'], this.onTriggerEvent.bind(this));
+ this._bindEventService.bind(this._selectOperatorElm, 'change', this.onTriggerEvent.bind(this));
}
/**
* Clear the filter value
*/
clear(shouldTriggerQuery = true) {
- if (this.$filterElm && this.$selectOperatorElm) {
+ if (this._filterElm && this._selectOperatorElm) {
this._clearFilterTriggered = true;
this._shouldTriggerQuery = shouldTriggerQuery;
this.searchTerms = [];
- this.$selectOperatorElm.val(0);
- this.$filterInputElm.val('');
+ this._selectOperatorElm.selectedIndex = 0;
+ this._filterInputElm.value = '';
this.onTriggerEvent(undefined);
}
}
@@ -123,26 +127,23 @@ export class CompoundInputFilter implements Filter {
* destroy the filter
*/
destroy() {
- if (this.$filterElm && this.$selectOperatorElm) {
- this.$filterElm.off('keyup blur change wheel').remove();
- this.$selectOperatorElm.off('change');
- }
- this.$filterElm = null;
- this.$selectOperatorElm = null;
+ this._bindEventService.unbindAll();
+ this._selectOperatorElm?.remove?.();
+ this._filterElm?.remove?.();
}
- /** Set value(s) on the DOM element */
+ /** Set value(s) on the DOM element */
setValues(values: SearchTerm[] | SearchTerm, operator?: OperatorType | OperatorString) {
if (values) {
const newValue = Array.isArray(values) ? values[0] : values;
- this.$filterInputElm.val(newValue);
+ this._filterInputElm.value = `${newValue ?? ''}`;
}
// set the operator, in the DOM as well, when defined
this.operator = operator || this.defaultOperator;
- if (operator && this.$selectOperatorElm) {
+ if (operator && this._selectOperatorElm) {
const operatorShorthand = mapOperatorToShorthandDesignation(this.operator);
- this.$selectOperatorElm.val(operatorShorthand);
+ this._selectOperatorElm.value = operatorShorthand;
}
}
@@ -150,13 +151,23 @@ export class CompoundInputFilter implements Filter {
// protected functions
// ------------------
- protected buildInputHtmlString() {
+ protected buildInputElement(): HTMLInputElement {
const columnId = this.columnDef?.id ?? '';
- let placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
- if (this.columnFilter && this.columnFilter.placeholder) {
+
+ // create the DOM element & add an ID and filter class
+ let placeholder = this.gridOptions?.defaultFilterPlaceholder ?? '';
+ if (this.columnFilter?.placeholder) {
placeholder = this.columnFilter.placeholder;
}
- return ``;
+
+ const inputElm = document.createElement('input');
+ inputElm.type = this._inputType || 'text';
+ inputElm.className = `form-control compound-input filter-${columnId}`;
+ inputElm.autocomplete = 'off';
+ inputElm.placeholder = placeholder;
+ inputElm.setAttribute('role', 'presentation');
+
+ return inputElm;
}
/** Get the available operator option values to populate the operator select dropdown list */
@@ -212,16 +223,22 @@ export class CompoundInputFilter implements Filter {
*/
protected createDomElement(searchTerm?: SearchTerm) {
const columnId = this.columnDef?.id ?? '';
- const $headerElm = this.grid.getHeaderRowColumn(columnId);
- $($headerElm).empty();
+ const headerElm = this.grid.getHeaderRowColumn(columnId);
+ emptyElement(headerElm);
// create the DOM Select dropdown for the Operator
- const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues());
- this.$selectOperatorElm = $(selectOperatorHtmlString);
- this.$filterInputElm = $(this.buildInputHtmlString());
- const $filterContainerElm = $(`
`);
- const $containerInputGroup = $(``);
- const $operatorInputGroupAddon = $(``);
+ this._selectOperatorElm = buildSelectOperator(this.getOperatorOptionValues());
+ this._filterInputElm = this.buildInputElement();
+ const emptySpanElm = document.createElement('span');
+
+ const filterContainerElm = document.createElement('div');
+ filterContainerElm.className = `form-group search-filter filter-${columnId}`;
+
+ const containerInputGroupElm = document.createElement('div');
+ containerInputGroupElm.className = 'input-group';
+
+ const operatorInputGroupAddonElm = document.createElement('div');
+ operatorInputGroupAddonElm.className = 'input-group-addon input-group-prepend operator';
/* the DOM element final structure will be
@@ -231,54 +248,55 @@ export class CompoundInputFilter implements Filter {
*/
- $operatorInputGroupAddon.append(this.$selectOperatorElm);
- $containerInputGroup.append($operatorInputGroupAddon);
- $containerInputGroup.append(this.$filterInputElm);
+ operatorInputGroupAddonElm.appendChild(this._selectOperatorElm);
+ containerInputGroupElm.appendChild(operatorInputGroupAddonElm);
+ containerInputGroupElm.appendChild(this._filterInputElm);
+ containerInputGroupElm.appendChild(emptySpanElm);
// create the DOM element & add an ID and filter class
- $filterContainerElm.append($containerInputGroup);
+ filterContainerElm.appendChild(containerInputGroupElm);
- this.$filterInputElm.val(searchTerm);
- this.$filterInputElm.data('columnId', columnId);
+ this._filterInputElm.value = `${searchTerm ?? ''}`;
+ this._filterInputElm.dataset.columnid = `${columnId}`;
if (this.operator) {
const operatorShorthand = mapOperatorToShorthandDesignation(this.operator);
- this.$selectOperatorElm.val(operatorShorthand);
+ this._selectOperatorElm.value = operatorShorthand;
}
// if there's a search term, we will add the "filled" class for styling purposes
if (searchTerm) {
- $filterContainerElm.addClass('filled');
+ this._filterInputElm.classList.add('filled');
}
// append the new DOM element to the header row
- if ($filterContainerElm && typeof $filterContainerElm.appendTo === 'function') {
- $filterContainerElm.appendTo($headerElm);
+ if (filterContainerElm) {
+ headerElm.appendChild(filterContainerElm);
}
- return $filterContainerElm;
+ return filterContainerElm;
}
/**
* Event trigger, could be called by the Operator dropdown or the input itself and we will cover the following (keyup, change, mousewheel & spinner)
* We will trigger the Filter Service callback from this handler
*/
- protected onTriggerEvent(event: KeyboardEvent | undefined) {
+ protected onTriggerEvent(event: Event | undefined) {
if (this._clearFilterTriggered) {
this.callback(event, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
- this.$filterElm.removeClass('filled');
+ this._filterElm.classList.remove('filled');
} else {
const eventType = event?.type ?? '';
- const selectedOperator = this.$selectOperatorElm.find('option:selected').val();
- let value = this.$filterInputElm.val() as string;
+ const selectedOperator = this._selectOperatorElm.value as OperatorString;
+ let value = this._filterInputElm.value as string;
const enableWhiteSpaceTrim = this.gridOptions.enableFilterTrimWhiteSpace || this.columnFilter.enableTrimWhiteSpace;
if (typeof value === 'string' && enableWhiteSpaceTrim) {
value = value.trim();
}
- (value !== null && value !== undefined && value !== '') ? this.$filterElm.addClass('filled') : this.$filterElm.removeClass('filled');
- const callbackArgs = { columnDef: this.columnDef, searchTerms: (value ? [value] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery };
- const typingDelay = (eventType === 'keyup' && event?.key !== 'Enter') ? this._debounceTypingDelay : 0;
+ (value !== null && value !== undefined && value !== '') ? this._filterElm.classList.add('filled') : this._filterElm.classList.remove('filled');
+ const callbackArgs = { columnDef: this.columnDef, searchTerms: (value ? [value] : null), operator: selectedOperator, shouldTriggerQuery: this._shouldTriggerQuery };
+ const typingDelay = (eventType === 'keyup' && (event as KeyboardEvent)?.key !== 'Enter') ? this._debounceTypingDelay : 0;
if (typingDelay > 0) {
clearTimeout(this.timer as NodeJS.Timeout);
diff --git a/packages/common/src/filters/compoundSliderFilter.ts b/packages/common/src/filters/compoundSliderFilter.ts
index d4ddae836..a35195619 100644
--- a/packages/common/src/filters/compoundSliderFilter.ts
+++ b/packages/common/src/filters/compoundSliderFilter.ts
@@ -11,8 +11,9 @@ import {
} from '../interfaces/index';
import { Constants } from '../constants';
import { OperatorString, OperatorType, SearchTerm } from '../enums/index';
-import { buildSelectOperatorHtmlString } from './filterUtilities';
-import { getTranslationPrefix, mapOperatorToShorthandDesignation } from '../services/utilities';
+import { buildSelectOperator } from './filterUtilities';
+import { emptyElement, getTranslationPrefix, mapOperatorToShorthandDesignation } from '../services/utilities';
+import { BindingEventService } from '../services/bindingEvent.service';
import { TranslaterService } from '../services/translater.service';
const DEFAULT_MIN_VALUE = 0;
@@ -20,22 +21,26 @@ const DEFAULT_MAX_VALUE = 100;
const DEFAULT_STEP = 1;
export class CompoundSliderFilter implements Filter {
+ protected _bindEventService: BindingEventService;
protected _clearFilterTriggered = false;
protected _currentValue?: number;
protected _shouldTriggerQuery = true;
protected _elementRangeInputId = '';
protected _elementRangeOutputId = '';
protected _operator?: OperatorType | OperatorString;
- protected $containerInputGroupElm: any;
- protected $filterElm: any;
- protected $filterInputElm: any;
- protected $selectOperatorElm: any;
+ protected containerInputGroupElm?: HTMLDivElement;
+ protected filterElm!: HTMLDivElement;
+ protected filterInputElm!: HTMLInputElement;
+ protected filterNumberElm?: HTMLSpanElement;
+ protected selectOperatorElm!: HTMLSelectElement;
grid!: SlickGrid;
searchTerms: SearchTerm[] = [];
columnDef!: Column;
callback!: FilterCallback;
- constructor(protected readonly translaterService: TranslaterService) { }
+ constructor(protected readonly translaterService: TranslaterService) {
+ this._bindEventService = new BindingEventService();
+ }
/** Getter for the Filter Operator */
get columnFilter(): ColumnFilter {
@@ -59,7 +64,7 @@ export class CompoundSliderFilter implements Filter {
/** Getter for the Grid Options pulled through the Grid Object */
protected get gridOptions(): GridOption {
- return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
+ return this.grid?.getOptions?.() ?? {};
}
/** Getter for the single Locale texts provided by the user in main file or else use default English locales via the Constants */
@@ -88,7 +93,7 @@ export class CompoundSliderFilter implements Filter {
this.callback = args.callback;
this.columnDef = args.columnDef;
this.operator = args.operator || '';
- this.searchTerms = (args.hasOwnProperty('searchTerms') ? args.searchTerms : []) || [];
+ this.searchTerms = args?.searchTerms ?? [];
// define the input & slider number IDs
this._elementRangeInputId = `rangeInput_${this.columnDef.field}`;
@@ -99,29 +104,17 @@ export class CompoundSliderFilter implements Filter {
// step 1, create the DOM Element of the filter which contain the compound Operator+Input
// and initialize it if searchTerm is filled
- this.$filterElm = this.createDomElement(searchTerm);
+ this.filterElm = this.createDomElement(searchTerm);
- // step 3, subscribe to the input change event and run the callback when that happens
+ // step 2, subscribe to the input change event and run the callback when that happens
// also add/remove "filled" class for styling purposes
- this.$filterInputElm.change((e: any) => {
- this.onTriggerEvent(e);
- });
- this.$selectOperatorElm.change((e: any) => {
- this.onTriggerEvent(e);
- });
+ this._bindEventService.bind(this.filterInputElm, 'change', this.onTriggerEvent.bind(this));
+ this._bindEventService.bind(this.selectOperatorElm, 'change', this.onTriggerEvent.bind(this));
// if user chose to display the slider number on the right side, then update it every time it changes
// we need to use both "input" and "change" event to be all cross-browser
if (!this.filterParams.hideSliderNumber) {
- this.$filterInputElm.on('input change', (e: { target: HTMLInputElement }) => {
- const value = e && e.target && e.target.value;
- if (value && document) {
- const elements = document.getElementsByClassName(this._elementRangeOutputId || '');
- if (elements && elements.length > 0 && elements[0].innerHTML) {
- elements[0].innerHTML = value;
- }
- }
- });
+ this._bindEventService.bind(this.filterInputElm, ['input', 'change'], this.handleInputChange.bind(this));
}
}
@@ -129,19 +122,19 @@ export class CompoundSliderFilter implements Filter {
* Clear the filter value
*/
clear(shouldTriggerQuery = true) {
- if (this.$filterElm && this.$selectOperatorElm) {
+ if (this.filterElm && this.selectOperatorElm) {
this._clearFilterTriggered = true;
this._shouldTriggerQuery = shouldTriggerQuery;
this.searchTerms = [];
- const clearedValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : DEFAULT_MIN_VALUE;
+ const clearedValue = this.filterParams?.sliderStartValue ?? DEFAULT_MIN_VALUE;
this._currentValue = +clearedValue;
- this.$selectOperatorElm.val(0);
- this.$filterInputElm.val(clearedValue);
- if (!this.filterParams.hideSliderNumber) {
- this.$containerInputGroupElm.children('div.input-group-addon.input-group-append').children().last().html(clearedValue);
+ this.selectOperatorElm.selectedIndex = 0;
+ this.filterInputElm.value = clearedValue;
+ if (this.filterNumberElm) {
+ this.filterNumberElm.textContent = clearedValue;
}
this.onTriggerEvent(undefined);
- this.$filterElm.removeClass('filled');
+ this.filterElm.classList.remove('filled');
}
}
@@ -149,13 +142,10 @@ export class CompoundSliderFilter implements Filter {
* destroy the filter
*/
destroy() {
- if (this.$filterInputElm) {
- this.$filterInputElm.off('input change').remove();
- this.$selectOperatorElm.off('change').remove();
- }
- this.$filterInputElm = null;
- this.$filterElm = null;
- this.$selectOperatorElm = null;
+ this._bindEventService.unbindAll();
+ this.selectOperatorElm?.remove?.();
+ emptyElement(this.filterElm);
+ this.filterElm?.remove?.();
}
/**
@@ -170,14 +160,16 @@ export class CompoundSliderFilter implements Filter {
setValues(values: SearchTerm | SearchTerm[], operator?: OperatorType | OperatorString) {
const newValue = Array.isArray(values) ? values[0] : values;
this._currentValue = +newValue;
- this.$filterInputElm.val(newValue);
- this.$containerInputGroupElm.children('div.input-group-addon.input-group-append').children().last().html(newValue);
+ this.filterInputElm.value = `${newValue ?? ''}`;
+ if (this.filterNumberElm) {
+ this.filterNumberElm.textContent = `${newValue ?? ''}`;
+ }
// set the operator, in the DOM as well, when defined
this.operator = operator || this.defaultOperator;
- if (operator && this.$selectOperatorElm) {
+ if (operator && this.selectOperatorElm) {
const operatorShorthand = mapOperatorToShorthandDesignation(this.operator);
- this.$selectOperatorElm.val(operatorShorthand);
+ this.selectOperatorElm.value = operatorShorthand;
}
}
@@ -185,26 +177,6 @@ export class CompoundSliderFilter implements Filter {
// protected functions
// ------------------
- /** Build HTML Template for the input range (slider) */
- protected buildTemplateHtmlString() {
- const minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
- const maxValue = this.filterProperties.hasOwnProperty('maxValue') ? this.filterProperties.maxValue : DEFAULT_MAX_VALUE;
- const defaultValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
- const step = this.filterProperties.hasOwnProperty('valueStep') ? this.filterProperties.valueStep : DEFAULT_STEP;
-
- return ``;
- }
-
- /** Build HTML Template for the text (number) that is shown appended to the slider */
- protected buildTemplateSliderTextHtmlString() {
- const minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
- const defaultValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
-
- return `${defaultValue}
`;
- }
-
/** Get the available operator option values to populate the operator select dropdown list */
protected getOperatorOptionValues(): OperatorDetail[] {
if (this.columnFilter?.compoundOperatorList) {
@@ -234,12 +206,15 @@ export class CompoundSliderFilter implements Filter {
/**
* Create the DOM element
*/
- protected createDomElement(searchTerm?: SearchTerm) {
+ protected createDomElement(searchTerm?: SearchTerm): HTMLDivElement {
const columnId = this.columnDef?.id ?? '';
- const minValue = (this.filterProperties.hasOwnProperty('minValue') && this.filterProperties.minValue) ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
- const startValue = +(this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue);
- const $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id);
- $($headerElm).empty();
+ const minValue = this.filterProperties?.minValue ?? DEFAULT_MIN_VALUE;
+ const maxValue = this.filterProperties?.maxValue ?? DEFAULT_MAX_VALUE;
+ const defaultValue = this.filterParams?.sliderStartValue ?? minValue;
+ const step = this.filterProperties?.valueStep ?? DEFAULT_STEP;
+ const startValue = +(this.filterParams?.sliderStartValue ?? minValue);
+ const headerElm = this.grid.getHeaderRowColumn(this.columnDef.id);
+ emptyElement(headerElm);
let searchTermInput = (searchTerm || '0') as string;
if (+searchTermInput < minValue) {
@@ -250,66 +225,100 @@ export class CompoundSliderFilter implements Filter {
}
this._currentValue = +searchTermInput;
- // create the DOM Select dropdown for the Operator
- const selectOperatorHtmlString = buildSelectOperatorHtmlString(this.getOperatorOptionValues());
- this.$selectOperatorElm = $(selectOperatorHtmlString);
- this.$filterInputElm = $(this.buildTemplateHtmlString());
- const $filterContainerElm = $(``);
- this.$containerInputGroupElm = $(``);
- const $operatorInputGroupAddon = $(``);
-
- /* the DOM element final structure will be
-