diff --git a/source/components/form/select.mjs b/source/components/form/select.mjs index 36c67751ab9bc3885037a6dcd05ba945cc98c1e3..143ae5e9fdaf3eaa9ab594548032cf7f4f1d350b 100644 --- a/source/components/form/select.mjs +++ b/source/components/form/select.mjs @@ -435,6 +435,7 @@ class Select extends CustomControl { * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0) * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array * @property {Boolean} features.storeFetchedData=false Store fetched data in the object + * @property {Boolean} features.useStrictValueComparison=true Use strict value comparison for the selection * @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled * @property {Object} templates Template definitions @@ -471,6 +472,7 @@ class Select extends CustomControl { closeOnSelect: false, emptyValueIfNoOptions: false, storeFetchedData: false, + useStrictValueComparison: false, }, url: null, labels: { @@ -566,7 +568,6 @@ class Select extends CustomControl { let lastValue = self.value; self[internalSymbol].attachObserver( - new Observer(function () { if (isObject(this) && this instanceof ProxyObserver) { const n = this.getSubject()?.options?.value; @@ -591,17 +592,17 @@ class Select extends CustomControl { } /** - * + * * @returns {*} * @throws {Error} storeFetchedData is not enabled * @since 3.66.0 */ getLastFetchedData() { - + if (this.getOption("features.storeFetchedData") === false) { throw new Error("storeFetchedData is not enabled"); } - + return this?.[lastFetchedDataSymbol]; } @@ -662,7 +663,7 @@ class Select extends CustomControl { * @return {Promise} */ fetch(url) { - + if (url instanceof URL) { url = url.toString(); } @@ -683,6 +684,8 @@ class Select extends CustomControl { new Processing(10, () => { + this.setOption("options", []); + fetchData .call(this, url) .then((map) => { @@ -693,14 +696,27 @@ class Select extends CustomControl { map instanceof Set || map instanceof Map ) { + + this.importOptions(map); this[lastFetchedDataSymbol] = map; - + + let result; + const selection = this.getOption("selection") + if (selection) { + result = setSelection.call(this, selection); + } else if (this.hasAttribute("value")) { + result = setSelection.call(this, this.getAttribute("value")); + } else { + result = setSelection.call(this, []); + } + setTimeout(() => { setStatusOrRemoveBadges.call(this, "closed"); resolve(); }, 10); - return; + + return result; } setStatusOrRemoveBadges.call(this, "error"); @@ -806,7 +822,7 @@ class Select extends CustomControl { data: map.get(value), }); }); - + runAsOptionLengthChanged.call(this, map.size); this.setOption("options", options); @@ -1022,11 +1038,31 @@ function buildSelectionLabel(value) { const options = this.getOption("options"); for (let i = 0; i < options.length; i++) { - const o = options?.[i]; - if (isObject(o) && o?.["value"] === value) { - return o?.["label"]; - } else if (isPrimitive(o) && o === value) { + let o = options?.[i]; + let l, v, v2; + + if (this.getOption("features.useStrictValueComparison") === true) { + v = value; + } else { + v = `${value}`; + } + + if (isPrimitive(o) && o === value) { return o; + } else if (!isObject(o)) { + continue; + } + + if (this.getOption("features.useStrictValueComparison") === true) { + l = o?.["label"] + v2 = o?.["value"] + } else { + l = `${o?.["label"]}`; + v2 = `${o?.["value"]}`; + } + + if (v2 === v) { + return l; } } @@ -1526,8 +1562,13 @@ function handleOptionKeyboardEvents(event) { case "Space": const path = event.composedPath(); const element = path?.[0]; - - fireEvent(element.getElementsByTagName("input"), "click"); + if (element instanceof HTMLElement) { + const input = element.getElementsByTagName("input") + if (!input) { + return; + } + fireEvent(input, "click"); + } event.preventDefault(); break; @@ -1672,6 +1713,7 @@ function focusFilter(focusOptions) { * @throws {Error} unsupported type */ function gatherState() { + const type = this.getOption("type"); if (["radio", "checkbox"].indexOf(type) === -1) { throw new Error("unsupported type"); @@ -1936,6 +1978,7 @@ function convertSelectionToValue(selection) { * @throws {Error} no shadow-root is defined */ function setSelection(selection) { + if (isString(selection)) { const result = convertValueToSelection.call(this, selection); selection = result?.selection; @@ -2073,33 +2116,13 @@ function show() { new Processing(200, () => { this.fetch() - .then(() => { - setTimeout(() => { - let result; - if (this.hasAttribute("value")) { - result = setSelection.call(this, this.getAttribute("value")); - } else { - result = setSelection.call(this, []); - } - - result - .then(() => { - show.call(this); - }) - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - }, 100); - }) .catch((e) => { addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); setStatusOrRemoveBadges.call(this, "error"); }); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); + }).run().catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); return; } @@ -2334,16 +2357,16 @@ function initEventHandler() { */ function setStatusOrRemoveBadges(suggestion) { setTimeout(() => { - + const selection = this.getOption("selection"); - + const clearAllFlag = isArray(selection) && selection.length > 0 && this.getOption("features.clearAll") === true; const current = this.getOption("classes.statusOrRemoveBadge"); - + if (this[isLoadingSymbol] === true) { if (current !== "loading") { this.setOption("classes.statusOrRemoveBadge", "loading");