diff --git a/packages/pluggableWidgets/combobox-web/CHANGELOG.md b/packages/pluggableWidgets/combobox-web/CHANGELOG.md index b43c5de8aa..3007958889 100644 --- a/packages/pluggableWidgets/combobox-web/CHANGELOG.md +++ b/packages/pluggableWidgets/combobox-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Changed + +- Moved the debounce interval for filtering operations from the Events tab to Advanced tab. + ## [2.5.1] - 2025-09-19 ### Fixed @@ -15,6 +19,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - We fixed an issue where combobox lazy load is not working on initial load. +### Added + +- We added the option to configure a debounce interval for datasource filter operations as well. + ## [2.5.0] - 2025-08-12 ### Added diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts index 7e7c05e751..392b732415 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.editorConfig.ts @@ -178,10 +178,6 @@ export function getProperties( hidePropertiesIn(defaultProperties, values, ["loadingType"]); } - if (values.onChangeFilterInputEvent === null) { - hidePropertiesIn(defaultProperties, values, ["filterInputDebounceInterval"]); - } - return defaultProperties; } diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.xml b/packages/pluggableWidgets/combobox-web/src/Combobox.xml index c1994358df..274e3ba9af 100644 --- a/packages/pluggableWidgets/combobox-web/src/Combobox.xml +++ b/packages/pluggableWidgets/combobox-web/src/Combobox.xml @@ -329,7 +329,6 @@ On leave - On filter input change @@ -337,10 +336,6 @@ - - Debounce interval - The debounce interval for each filter input change event triggered in milliseconds. - @@ -439,6 +434,10 @@ None + + Debounce interval + The debounce interval for each filter input change event triggered in milliseconds. + diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts index eb910d4a4e..a4e65f8c16 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/BaseAssociationSelector.ts @@ -27,9 +27,9 @@ export class BaseAssociationSelector = new Map(); private lazyLoader: LazyLoadProvider = new LazyLoadProvider(); - constructor() { + constructor(props: { filterInputDebounceInterval: number }) { this.caption = new AssociationSimpleCaptionsProvider(this._valuesMap); - this.options = new AssociationOptionsProvider(this.caption, this._valuesMap); + this.options = new AssociationOptionsProvider(this.caption, this._valuesMap, props.filterInputDebounceInterval); } updateProps(props: ComboboxContainerProps): void { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts index ac0e0a99f2..1cc1e97959 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Association/utils.ts @@ -28,13 +28,15 @@ type ExtractionReturnValue = [ ListWidgetValue | undefined, OptionsSourceAssociationCustomContentTypeEnum, boolean, - LoadingTypeEnum + LoadingTypeEnum, + number ]; export function extractAssociationProps(props: ComboboxContainerProps): ExtractionReturnValue { const attr = props.attributeAssociation; const filterType = props.filterType; const onChangeEvent = props.onChangeEvent; + const filterInputDebounceInterval = props.filterInputDebounceInterval; if (!attr) { throw new Error("'optionsSourceType' type is 'association' but 'attributeAssociation' is not defined."); @@ -79,6 +81,7 @@ export function extractAssociationProps(props: ComboboxContainerProps): Extracti customContent, customContentType, lazyLoading, - loadingType + loadingType, + filterInputDebounceInterval ]; } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts index 1fbd1ae76a..9d2bb92632 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/BaseDatasourceOptionsProvider.ts @@ -1,27 +1,38 @@ +import { debounce } from "@mendix/widget-plugin-platform/utils/debounce"; import { ListAttributeValue, ListValue, ObjectItem } from "mendix"; import { FilterTypeEnum } from "../../typings/ComboboxProps"; import { BaseOptionsProvider } from "./BaseOptionsProvider"; import { datasourceFilter } from "./datasourceFilter"; import { CaptionsProvider, SortOrder, Status } from "./types"; import { DEFAULT_LIMIT_SIZE } from "./utils"; +import { FilterCondition } from "mendix/filters"; export interface BaseProps { attributeId?: ListAttributeValue["id"]; ds: ListValue; filterType: FilterTypeEnum; lazyLoading: boolean; + filterInputDebounceInterval?: number; } export class BaseDatasourceOptionsProvider extends BaseOptionsProvider { private ds?: ListValue; private attributeId?: ListAttributeValue["id"]; protected loading: boolean = false; + private debouncedSetFilter: (filterCondition: FilterCondition | undefined) => void; constructor( caption: CaptionsProvider, - protected valuesMap: Map + protected valuesMap: Map, + filterInputDebounceInterval: number = 200 ) { super(caption); + + const [debouncedFn] = debounce((filterCondition: FilterCondition | undefined) => { + this.ds?.setFilter(filterCondition); + }, filterInputDebounceInterval); + + this.debouncedSetFilter = debouncedFn; } get sortOrder(): SortOrder { @@ -51,10 +62,10 @@ export class BaseDatasourceOptionsProvider extends BaseOptionsProvider = new Map(); selectedItemsSorting: SelectedItemsSortingEnum = "none"; - constructor() { + constructor(props: { filterInputDebounceInterval: number }) { this.caption = new DatabaseCaptionsProvider(this._objectsMap); - this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap); + this.options = new DatabaseOptionsProvider(this.caption, this._objectsMap, props.filterInputDebounceInterval); } getOptions(): string[] { diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts index d480133072..55944a48fe 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/DatabaseSingleSelectionSelector.ts @@ -33,9 +33,9 @@ export class DatabaseSingleSelectionSelector | undefined; + filterInputDebounceInterval: number; }; export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionReturnValue { const targetAttribute = props.databaseAttributeString; const filterType = props.filterType; - + const filterInputDebounceInterval = props.filterInputDebounceInterval; const ds = props.optionsSourceDatabaseDataSource; if (!ds) { throw new Error("'optionsSourceType' type is 'database' but 'optionsSourceDatabaseDataSource' is not defined."); @@ -83,7 +84,8 @@ export function extractDatabaseProps(props: ComboboxContainerProps): ExtractionR filterType, lazyLoading, loadingType, - valueSourceAttribute + valueSourceAttribute, + filterInputDebounceInterval }; } diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts b/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts index 7bc6005f66..4667dc363c 100644 --- a/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts +++ b/packages/pluggableWidgets/combobox-web/src/helpers/getSelector.ts @@ -13,16 +13,20 @@ export function getSelector(props: ComboboxContainerProps): Selector { return new EnumBooleanSingleSelector(); } else if (props.optionsSourceType === "association") { return props.attributeAssociation.type === "Reference" - ? new AssociationSingleSelector() - : new AssociationMultiSelector(); + ? new AssociationSingleSelector({ filterInputDebounceInterval: props.filterInputDebounceInterval }) + : new AssociationMultiSelector({ filterInputDebounceInterval: props.filterInputDebounceInterval }); } else { throw new Error(`'optionsSourceType' of type '${props.optionsSourceType}' is not supported`); } } else if (props.source === "database") { if (props.optionsSourceDatabaseItemSelection?.type === "Multi") { - return new DatabaseMultiSelectionSelector(); + return new DatabaseMultiSelectionSelector({ + filterInputDebounceInterval: props.filterInputDebounceInterval + }); } else { - return new DatabaseSingleSelectionSelector(); + return new DatabaseSingleSelectionSelector({ + filterInputDebounceInterval: props.filterInputDebounceInterval + }); } } else if (props.source === "static") { return new StaticSingleSelector(); diff --git a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts index aec3e503fb..fcc265d859 100644 --- a/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts +++ b/packages/pluggableWidgets/combobox-web/typings/ComboboxProps.d.ts @@ -90,7 +90,6 @@ export interface ComboboxContainerProps { onEnterEvent?: ActionValue; onLeaveEvent?: ActionValue; onChangeFilterInputEvent?: ActionValue<{ filterInput: Option }>; - filterInputDebounceInterval: number; ariaRequired: DynamicValue; ariaLabel?: DynamicValue; clearButtonAriaLabel?: DynamicValue; @@ -102,6 +101,7 @@ export interface ComboboxContainerProps { loadingType: LoadingTypeEnum; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; + filterInputDebounceInterval: number; } export interface ComboboxPreviewProps { @@ -148,7 +148,6 @@ export interface ComboboxPreviewProps { onEnterEvent: {} | null; onLeaveEvent: {} | null; onChangeFilterInputEvent: {} | null; - filterInputDebounceInterval: number | null; ariaRequired: string; ariaLabel: string; clearButtonAriaLabel: string; @@ -160,4 +159,5 @@ export interface ComboboxPreviewProps { loadingType: LoadingTypeEnum; selectedItemsSorting: SelectedItemsSortingEnum; filterType: FilterTypeEnum; + filterInputDebounceInterval: number | null; }