Fix infinite loop in missingOption in country/state due to not waiting for results

Add class method to search through select options
This commit is contained in:
nathan 2023-12-05 11:51:24 -07:00
parent c400b548e8
commit 6f4fdb4707
5 changed files with 50 additions and 19 deletions

View File

@ -167,6 +167,27 @@ export const Et2WidgetWithSelectMixin = <T extends Constructor<LitElement>>(supe
return [this.value]; 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 * Render select_options as child DOM Nodes
* @protected * @protected

View File

@ -377,21 +377,10 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
} }
if(this.searchEnabled) 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 // Check to see if value is for an option we do not have
for(const newValueElement of this.getValueAsArray()) for(const newValueElement of this.getValueAsArray())
{ {
if(search(this.select_options, newValueElement)) if(this.optionSearch(newValueElement))
{ {
continue; continue;
} }

View File

@ -37,7 +37,7 @@ export class Et2SelectCountry extends Et2StaticSelectMixin(Et2Select)
this.search = true; this.search = true;
(<Promise<SelectOption[]>>so.country(this, {}, true)).then(options => this.fetchComplete = (<Promise<SelectOption[]>>so.country(this, {}, true)).then(options =>
{ {
this._static_options = options this._static_options = options
this.requestUpdate("select_options"); this.requestUpdate("select_options");

View File

@ -1,6 +1,6 @@
import {Et2Select} from "../Et2Select"; import {Et2Select} from "../Et2Select";
import {Et2StaticSelectMixin, StaticOptions} from "../StaticOptions"; import {Et2StaticSelectMixin, StaticOptions as so} from "../StaticOptions";
import {SelectOption} from "../FindSelectOptions"; import {cleanSelectOptions, SelectOption} from "../FindSelectOptions";
export class Et2SelectState extends Et2StaticSelectMixin(Et2Select) export class Et2SelectState extends Et2StaticSelectMixin(Et2Select)
{ {
@ -32,8 +32,11 @@ export class Et2SelectState extends Et2StaticSelectMixin(Et2Select)
set countryCode(code : string) set countryCode(code : string)
{ {
this.__countryCode = code; this.__countryCode = code;
this._static_options = <SelectOption[]>StaticOptions.state(this, {country_code: code}); this.fetchComplete = so.state(this, {country_code: code}).then((options : SelectOption[]) =>
this.requestUpdate("select_options"); {
this._static_options = cleanSelectOptions(options);
this.requestUpdate();
});
} }
set_country_code(code) set_country_code(code)

View File

@ -90,6 +90,24 @@ export const Et2StaticSelectMixin = <T extends Constructor<Et2WidgetWithSelect>>
} }
} }
/**
* 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 * 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. * 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); return this.cached_server_side(widget, 'select-country', options, return_promise);
} }
state(widget : Et2SelectWidgets, attrs) : SelectOption[] | Promise<SelectOption[]> state(widget : Et2SelectWidgets, attrs) : Promise<SelectOption[]>
{ {
var options = attrs.country_code ? attrs.country_code : 'de'; var options = attrs.country_code ? attrs.country_code : 'de';
return this.cached_server_side(widget, 'select-state', options); return <Promise<SelectOption[]>>this.cached_server_side(widget, 'select-state', options, true);
} }
dow(widget : Et2SelectWidgets, attrs) : Promise<SelectOption[]> dow(widget : Et2SelectWidgets, attrs) : Promise<SelectOption[]>