From 5ef349f0573e00a20594b184e059945ed7dc6da5 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 5 Dec 2023 11:51:24 -0700 Subject: [PATCH] Fix infinite loop in missingOption in country/state due to not waiting for results Add class method to search through select options --- .../Et2Select/Et2WidgetWithSelectMixin.ts | 21 ++++++++++++++++++ api/js/etemplate/Et2Select/SearchMixin.ts | 13 +---------- .../Et2Select/Select/Et2SelectCountry.ts | 2 +- .../Et2Select/Select/Et2SelectState.ts | 11 ++++++---- api/js/etemplate/Et2Select/StaticOptions.ts | 22 +++++++++++++++++-- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts index 449adac54c..ec613a373c 100644 --- a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts +++ b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts @@ -167,6 +167,27 @@ export const Et2WidgetWithSelectMixin = >(supe return [this.value]; } + /** + * Search options for a given value, returning the first matching option + * + * @return SelectOption | null + */ + public optionSearch(value : string, options : SelectOption[] = null) : SelectOption | null + { + let search = function(options, value) + { + return options.find((option) => + { + if(Array.isArray(option.value)) + { + return search(option.value, value); + } + return option.value == value; + }); + } + return search(options ?? this.select_options, value); + } + /** * Render select_options as child DOM Nodes * @protected diff --git a/api/js/etemplate/Et2Select/SearchMixin.ts b/api/js/etemplate/Et2Select/SearchMixin.ts index 9a7c978004..3657536ec4 100644 --- a/api/js/etemplate/Et2Select/SearchMixin.ts +++ b/api/js/etemplate/Et2Select/SearchMixin.ts @@ -377,21 +377,10 @@ export const Et2WithSearchMixin = dedupeMixin( } if(this.searchEnabled) { - let search = function(options, value) - { - return options.some((option) => - { - if(Array.isArray(option.value)) - { - return search(option.value, value); - } - return option.value == value; - }); - }; // Check to see if value is for an option we do not have for(const newValueElement of this.getValueAsArray()) { - if(search(this.select_options, newValueElement)) + if(this.optionSearch(newValueElement)) { continue; } diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectCountry.ts b/api/js/etemplate/Et2Select/Select/Et2SelectCountry.ts index 4c364c0837..4016088989 100644 --- a/api/js/etemplate/Et2Select/Select/Et2SelectCountry.ts +++ b/api/js/etemplate/Et2Select/Select/Et2SelectCountry.ts @@ -37,7 +37,7 @@ export class Et2SelectCountry extends Et2StaticSelectMixin(Et2Select) this.search = true; - (>so.country(this, {}, true)).then(options => + this.fetchComplete = (>so.country(this, {}, true)).then(options => { this._static_options = options this.requestUpdate("select_options"); diff --git a/api/js/etemplate/Et2Select/Select/Et2SelectState.ts b/api/js/etemplate/Et2Select/Select/Et2SelectState.ts index 9c1ac5336b..9341eb738d 100644 --- a/api/js/etemplate/Et2Select/Select/Et2SelectState.ts +++ b/api/js/etemplate/Et2Select/Select/Et2SelectState.ts @@ -1,6 +1,6 @@ import {Et2Select} from "../Et2Select"; -import {Et2StaticSelectMixin, StaticOptions} from "../StaticOptions"; -import {SelectOption} from "../FindSelectOptions"; +import {Et2StaticSelectMixin, StaticOptions as so} from "../StaticOptions"; +import {cleanSelectOptions, SelectOption} from "../FindSelectOptions"; export class Et2SelectState extends Et2StaticSelectMixin(Et2Select) { @@ -32,8 +32,11 @@ export class Et2SelectState extends Et2StaticSelectMixin(Et2Select) set countryCode(code : string) { this.__countryCode = code; - this._static_options = StaticOptions.state(this, {country_code: code}); - this.requestUpdate("select_options"); + this.fetchComplete = so.state(this, {country_code: code}).then((options : SelectOption[]) => + { + this._static_options = cleanSelectOptions(options); + this.requestUpdate(); + }); } set_country_code(code) diff --git a/api/js/etemplate/Et2Select/StaticOptions.ts b/api/js/etemplate/Et2Select/StaticOptions.ts index ee772f5418..c59b60c664 100644 --- a/api/js/etemplate/Et2Select/StaticOptions.ts +++ b/api/js/etemplate/Et2Select/StaticOptions.ts @@ -90,6 +90,24 @@ export const Et2StaticSelectMixin = > } } + /** + * Override the parent _missingOption to wait for server-side options + * to come back before we check to see if the value is not there. + * + * @param {string} newValueElement + * @protected + */ + protected _missingOption(newValueElement : string) + { + this.fetchComplete.then(() => + { + if(this.optionSearch(newValueElement) == null) + { + super._missingOption(newValueElement); + } + }) + } + /** * Override the parent fix_bad_value() to wait for server-side options * to come back before we check to see if the value is not there. @@ -381,10 +399,10 @@ export const StaticOptions = new class StaticOptionsType return this.cached_server_side(widget, 'select-country', options, return_promise); } - state(widget : Et2SelectWidgets, attrs) : SelectOption[] | Promise + state(widget : Et2SelectWidgets, attrs) : Promise { var options = attrs.country_code ? attrs.country_code : 'de'; - return this.cached_server_side(widget, 'select-state', options); + return >this.cached_server_side(widget, 'select-state', options, true); } dow(widget : Et2SelectWidgets, attrs) : Promise