From 6b67a83ad2d594084535272e57df37248e13538c Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 8 Nov 2024 00:00:47 -0500 Subject: [PATCH] fix(editor): add missing `changeEditorOption()` for Composite Editor --- .../src/examples/example12.ts | 5 +- .../editors/__tests__/sliderEditor.spec.ts | 68 +++++++++++++++++-- .../common/src/editors/autocompleterEditor.ts | 2 +- packages/common/src/editors/checkboxEditor.ts | 4 +- packages/common/src/editors/dateEditor.ts | 2 +- packages/common/src/editors/floatEditor.ts | 2 +- packages/common/src/editors/inputEditor.ts | 2 +- packages/common/src/editors/selectEditor.ts | 2 +- packages/common/src/editors/sliderEditor.ts | 45 ++++++++++-- packages/common/src/filters/sliderFilter.ts | 2 +- .../src/interfaces/sliderOption.interface.ts | 12 ++-- .../src/slick-composite-editor.component.ts | 2 +- 12 files changed, 121 insertions(+), 27 deletions(-) diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts index b31a78ebc..a1eb57d68 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example12.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example12.ts @@ -628,10 +628,11 @@ export default class Example12 { } // you can also change some editor options - // not all Editors supports this functionality, so far only these Editors are supported: AutoComplete, Date Single/Multiple Select + // not all Editors supports this functionality, so far only these Editors are supported are: Date, Single/Multiple Select, Slider /* if (columnDef.id === 'completed') { - this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'filter', true); // multiple-select.js, show filter in dropdown + this.compositeEditorInstance.changeFormEditorOption('complexity', 'filter', true); // multiple-select dropdown editor + this.compositeEditorInstance.changeFormEditorOption('percentComplete', 'hideSliderNumber', formValues['completed']); // slider editor this.compositeEditorInstance.changeFormEditorOption('finish', 'range', { min: 'today' }); // calendar picker, change minDate to today } */ diff --git a/packages/common/src/editors/__tests__/sliderEditor.spec.ts b/packages/common/src/editors/__tests__/sliderEditor.spec.ts index f0640f9fa..62ab57325 100644 --- a/packages/common/src/editors/__tests__/sliderEditor.spec.ts +++ b/packages/common/src/editors/__tests__/sliderEditor.spec.ts @@ -257,7 +257,65 @@ describe('SliderEditor', () => { expect(cellMouseEnterSpy).toHaveBeenCalledWith({ column: mockColumn, grid: gridStub }, expect.anything()); }); - describe('isValueChanged method', () => { + describe('changeEditorOption() method', () => { + it('should be able to change enableSliderTrackColoring option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('enableSliderTrackColoring', true); + + expect(editor.editorOptions.enableSliderTrackColoring).toBe(true); + }); + + it('should be able to change hideSliderNumber option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('hideSliderNumber', true); + + expect(editor.editorOptions.hideSliderNumber).toBe(true); + }); + + it('should be able to change maxValue option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('maxValue', 33); + + expect(editor.sliderOptions?.maxValue).toBe(33); + }); + + it('should be able to change minValue option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('minValue', 4); + + expect(editor.sliderOptions?.minValue).toBe(4); + }); + + it('should be able to change step option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('step', 5); + + expect(editor.sliderOptions?.step).toBe(5); + }); + + it('should be able to change sliderStartValue option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('sliderStartValue', 33); + + expect(editor.editorOptions.sliderStartValue).toBe(33); + }); + + it('should be able to change sliderTrackBackground option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('sliderTrackBackground', '#fff'); + + expect(editor.sliderOptions?.sliderTrackBackground).toBe('#fff'); + }); + + it('should be able to change sliderTrackFilledColor option', () => { + editor = new SliderEditor(editorArguments); + editor.changeEditorOption('sliderTrackFilledColor', '#fff'); + + expect(editor.editorOptions.sliderTrackFilledColor).toBe('#fff'); + }); + }); + + describe('isValueChanged() method', () => { it('should return True when previously dispatched change event is a different slider input number', () => { mockColumn.editor!.editorOptions = { sliderStartValue: 5 }; mockItemData = { id: 1, price: 32, isActive: true }; @@ -305,7 +363,7 @@ describe('SliderEditor', () => { }); }); - describe('applyValue method', () => { + describe('applyValue() method', () => { it('should apply the value to the price property when it passes validation', () => { mockColumn.editor!.validator = null as any; mockItemData = { id: 1, price: 456, isActive: true }; @@ -343,7 +401,7 @@ describe('SliderEditor', () => { }); }); - describe('serializeValue method', () => { + describe('serializeValue() method', () => { it('should return serialized value as a number', () => { mockItemData = { id: 1, price: 33, isActive: true }; @@ -407,7 +465,7 @@ describe('SliderEditor', () => { }); }); - describe('save method', () => { + describe('save() method', () => { afterEach(() => { vi.clearAllMocks(); }); @@ -472,7 +530,7 @@ describe('SliderEditor', () => { }); }); - describe('validate method', () => { + describe('validate() method', () => { it('should return False when field is required and field is empty', () => { mockColumn.editor!.required = true; editor = new SliderEditor(editorArguments); diff --git a/packages/common/src/editors/autocompleterEditor.ts b/packages/common/src/editors/autocompleterEditor.ts index 0b2d455c7..77374a89b 100644 --- a/packages/common/src/editors/autocompleterEditor.ts +++ b/packages/common/src/editors/autocompleterEditor.ts @@ -89,7 +89,7 @@ export class AutocompleterEditor implements Ed } // get locales provided by user in forRoot or else use default English locales via the Constants - this._locales = this.gridOptions && this.gridOptions.locales || Constants.locales; + this._locales = this.gridOptions?.locales || Constants.locales; this.init(); } diff --git a/packages/common/src/editors/checkboxEditor.ts b/packages/common/src/editors/checkboxEditor.ts index 889926b8d..1f8fcee81 100644 --- a/packages/common/src/editors/checkboxEditor.ts +++ b/packages/common/src/editors/checkboxEditor.ts @@ -175,7 +175,7 @@ export class CheckboxEditor implements Editor { } applyValue(item: any, state: any): void { - const fieldName = this.columnDef && this.columnDef.field; + const fieldName = this.columnDef?.field; if (fieldName !== undefined) { const isComplexObject = fieldName?.indexOf('.') > 0; // is the field a complex object, "address.streetNumber" @@ -203,7 +203,7 @@ export class CheckboxEditor implements Editor { } loadValue(item: any): void { - const fieldName = this.columnDef && this.columnDef.field; + const fieldName = this.columnDef?.field; if (item && fieldName !== undefined && this._input) { // is the field a complex object, "address.streetNumber" diff --git a/packages/common/src/editors/dateEditor.ts b/packages/common/src/editors/dateEditor.ts index b3b085a67..7886800eb 100644 --- a/packages/common/src/editors/dateEditor.ts +++ b/packages/common/src/editors/dateEditor.ts @@ -281,7 +281,7 @@ export class DateEditor implements Editor { * @param {string} optionName * @param {newValue} newValue */ - changeEditorOption>(optionName: T, newValue: K): void { + changeEditorOption, K extends Required[T]>(optionName: T, newValue: K): void { if (!this.columnEditor.editorOptions) { this.columnEditor.editorOptions = {}; } diff --git a/packages/common/src/editors/floatEditor.ts b/packages/common/src/editors/floatEditor.ts index 23e84b227..1dd12190b 100644 --- a/packages/common/src/editors/floatEditor.ts +++ b/packages/common/src/editors/floatEditor.ts @@ -9,7 +9,7 @@ export class FloatEditor extends InputEditor { } loadValue(item: any): void { - const fieldName = this.columnDef && this.columnDef.field; + const fieldName = this.columnDef?.field; if (fieldName !== undefined) { diff --git a/packages/common/src/editors/inputEditor.ts b/packages/common/src/editors/inputEditor.ts index b0f42c22b..9c9055121 100644 --- a/packages/common/src/editors/inputEditor.ts +++ b/packages/common/src/editors/inputEditor.ts @@ -221,7 +221,7 @@ export class InputEditor implements Editor { } applyValue(item: any, state: any): void { - const fieldName = this.columnDef && this.columnDef.field; + const fieldName = this.columnDef?.field; if (fieldName !== undefined) { const isComplexObject = fieldName?.indexOf('.') > 0; // is the field a complex object, "address.streetNumber" diff --git a/packages/common/src/editors/selectEditor.ts b/packages/common/src/editors/selectEditor.ts index cb7869639..ba4bacefb 100644 --- a/packages/common/src/editors/selectEditor.ts +++ b/packages/common/src/editors/selectEditor.ts @@ -493,7 +493,7 @@ export class SelectEditor implements Editor { * @param {string} optionName - MultipleSelect option name * @param {newValue} newValue - MultipleSelect new option value */ - changeEditorOption(optionName: keyof MultipleSelectOption, newValue: any): void { + changeEditorOption, K extends Required[T]>(optionName: T, newValue: K): void { if (this.columnEditor) { if (!this.columnEditor.editorOptions) { this.columnEditor.editorOptions = {}; diff --git a/packages/common/src/editors/sliderEditor.ts b/packages/common/src/editors/sliderEditor.ts index ad41b40f5..62d8b768f 100644 --- a/packages/common/src/editors/sliderEditor.ts +++ b/packages/common/src/editors/sliderEditor.ts @@ -211,6 +211,35 @@ export class SliderEditor implements Editor { } } + /** + * Dynamically change an Editor option, this is especially useful with Composite Editor + * since this is the only way to change option after the Editor is created (for example dynamically change "minDate" or another Editor) + * @param {string} optionName - Slider editor option name + * @param {newValue} newValue - Slider editor new option value + */ + changeEditorOption, K extends Required<(CurrentSliderOption & SliderOption)>[T]>(optionName: T, newValue: K): void { + if (this.columnEditor) { + this.columnEditor.editorOptions ??= {}; + this.columnEditor.editorOptions[optionName] = newValue; + (this._sliderOptions as any)[optionName] = newValue; + + switch (optionName) { + case 'hideSliderNumber': + this.renderSliderNumber(this._editorElm, 0); + break; + case 'sliderStartValue': + this._inputElm.value = `${newValue}`; + this._inputElm.defaultValue = `${newValue}`; + break; + case 'maxValue': + case 'minValue': + case 'step': + this._inputElm[optionName.replace('Value', '') as 'min' | 'max' | 'step'] = `${newValue}`; + break; + } + } + } + isValueChanged(): boolean { const elmValue = this._inputElm?.value ?? ''; return (!(elmValue === '' && this._originalValue === undefined)) && (+elmValue !== this._originalValue); @@ -335,6 +364,15 @@ export class SliderEditor implements Editor { sliderInputContainerElm.appendChild(this._inputElm); divContainerElm.appendChild(sliderInputContainerElm); + this.renderSliderNumber(divContainerElm, defaultValue); + + // merge options with optional user's custom options + this._sliderOptions = { minValue, maxValue, step }; + + return divContainerElm; + } + + protected renderSliderNumber(divContainerElm: HTMLDivElement, defaultValue: number | string): void { if (!this.editorOptions.hideSliderNumber) { divContainerElm.classList.add('input-group'); @@ -342,12 +380,9 @@ export class SliderEditor implements Editor { this._sliderNumberElm = createDomElement('span', { className: `input-group-text`, textContent: `${defaultValue}` }); divGroupAddonElm.appendChild(this._sliderNumberElm); divContainerElm.appendChild(divGroupAddonElm); + } else { + divContainerElm.querySelector('.slider-value')?.remove(); } - - // merge options with optional user's custom options - this._sliderOptions = { minValue, maxValue, step }; - - return divContainerElm; } /** when it's a Composite Editor, we'll check if the Editor is editable (by checking onBeforeEditCell) and if not Editable we'll disable the Editor */ diff --git a/packages/common/src/filters/sliderFilter.ts b/packages/common/src/filters/sliderFilter.ts index 702b54874..94862d6d2 100644 --- a/packages/common/src/filters/sliderFilter.ts +++ b/packages/common/src/filters/sliderFilter.ts @@ -133,7 +133,7 @@ export class SliderFilter implements Filter { this._shouldTriggerQuery = shouldTriggerQuery; this.searchTerms = []; const lowestValue = +(this.filterOptions?.sliderStartValue ?? Constants.SLIDER_DEFAULT_MIN_VALUE) as number; - const highestValue = +(this.filterOptions?.sliderEndValue ?? Constants.SLIDER_DEFAULT_MAX_VALUE) as number; + const highestValue = +((this.filterOptions as SliderRangeOption)?.sliderEndValue ?? Constants.SLIDER_DEFAULT_MAX_VALUE) as number; if (this.sliderType === 'double') { if (this._sliderLeftInputElm) { diff --git a/packages/common/src/interfaces/sliderOption.interface.ts b/packages/common/src/interfaces/sliderOption.interface.ts index 68ba67fac..bcb7add6b 100644 --- a/packages/common/src/interfaces/sliderOption.interface.ts +++ b/packages/common/src/interfaces/sliderOption.interface.ts @@ -8,22 +8,22 @@ export interface SliderOption { /** Defaults to true, hide the slider number shown on the right side */ hideSliderNumber?: boolean; - /** Slider max end value */ - sliderEndValue?: number; - /** Slider min start value */ sliderStartValue?: number; /** Defaults to "#3C97DD", what will be the color to use to represent slider range */ sliderTrackFilledColor?: string; - - /** Defaults to 0, minimum value gap before reaching the maximum end value */ - stopGapBetweenSliderHandles?: number; } export interface SliderRangeOption extends Omit { /** Defaults to false, hide the slider numbers shown on the left/right side */ hideSliderNumbers?: boolean; + + /** Slider max end value */ + sliderEndValue?: number; + + /** Defaults to 0, minimum value gap before reaching the maximum end value */ + stopGapBetweenSliderHandles?: number; } export interface CurrentSliderOption { diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.ts b/packages/composite-editor-component/src/slick-composite-editor.component.ts index 5d6d26646..69a0b99a7 100644 --- a/packages/composite-editor-component/src/slick-composite-editor.component.ts +++ b/packages/composite-editor-component/src/slick-composite-editor.component.ts @@ -234,7 +234,7 @@ export class SlickCompositeEditorComponent implements ExternalResource { if (editor?.changeEditorOption) { editor.changeEditorOption(optionName, newOptionValue); } else { - throw new Error(`Editor with column id "${columnId}" not found OR the Editor does not support "changeEditorOption" (current only available with AutoComplete, Date, MultipleSelect & SingleSelect Editors).`); + throw new Error(`Editor with column id "${columnId}" not found OR the Editor does not support "changeEditorOption" (current only available with Date, MultipleSelect, SingleSelect & Slider Editors).`); } }