diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts
index 3b81abf41f..7898400343 100644
--- a/api/js/etemplate/Et2Select/Et2Select.ts
+++ b/api/js/etemplate/Et2Select/Et2Select.ts
@@ -9,7 +9,7 @@
import {LionSelect} from "@lion/select";
-import {css, html, PropertyValues, render, repeat, TemplateResult} from "@lion/core";
+import {css, html, PropertyValues, TemplateResult} from "@lion/core";
import {cssImage} from "../Et2Widget/Et2Widget";
import {StaticOptions} from "./StaticOptions";
import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin";
@@ -73,37 +73,35 @@ export class Et2Select extends Et2WidgetWithSelect
this.querySelector('select').append(...this.querySelectorAll('option'));
// if _inputNode was not available by the time set_value() got called
- if (this.getValue() !== this.modelValue)
+ if(this.getValue() !== this.modelValue)
{
this.set_value(this.modelValue);
}
}
+ /**
+ * Get the node where we're putting the selection options
+ *
+ * @returns {HTMLElement}
+ */
+ get _optionTargetNode() : HTMLElement
+ {
+ return this._inputNode;
+ }
+
/** @param {import('@lion/core').PropertyValues } changedProperties */
updated(changedProperties : PropertyValues)
{
super.updated(changedProperties);
- if(changedProperties.has('select_options'))
- {
- // Add in actual options as children to select
- if(this._inputNode)
- {
- // We use this.get_select_options() instead of this.select_options so children can override
- // This is how sub-types get their options in
- render(html`${this._emptyLabelTemplate()}
- ${repeat(this.get_select_options(), (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`,
- this._inputNode
- );
- }
- }
- if (changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('empty_label'))
+
+ if(changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('empty_label'))
{
// value not in options AND NOT (having an empty label and value)
- if (this.get_select_options().length > 0 && this.get_select_options().filter((option) => option.value == this.modelValue).length === 0 &&
- !(typeof this.empty_label !== 'undefined' && (this.modelValue||"") === ""))
+ if(this.get_select_options().length > 0 && this.get_select_options().filter((option) => option.value == this.modelValue).length === 0 &&
+ !(typeof this.empty_label !== 'undefined' && (this.modelValue || "") === ""))
{
// --> use first option
- this.modelValue = ""+this.get_select_options()[0]?.value; // ""+ to cast value of 0 to "0", to not replace with ""
+ this.modelValue = "" + this.get_select_options()[0]?.value; // ""+ to cast value of 0 to "0", to not replace with ""
}
// Re-set value, the option for it may have just shown up
this._inputNode.value = this.modelValue || "";
diff --git a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
index 68130fef72..22e7a8b172 100644
--- a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
+++ b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
@@ -9,7 +9,7 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {StaticOptions} from "./StaticOptions";
-import {dedupeMixin, html, PropertyValues, TemplateResult} from "@lion/core";
+import {dedupeMixin, html, PropertyValues, render, repeat, TemplateResult} from "@lion/core";
import {et2_readAttrWithDefault} from "../et2_core_xml";
import {find_select_options, SelectOption} from "./FindSelectOptions";
@@ -17,6 +17,37 @@ import {find_select_options, SelectOption} from "./FindSelectOptions";
* Base class for things that do selectbox type behaviour, to avoid putting too much or copying into read-only
* selectboxes, also for common handling of properties for more special selectboxes.
*
+ * As with most other widgets that extend Lion components, do not override render().
+ * To extend this mixin, override:
+ * - _optionTargetNode(): Return the HTMLElement where the "options" go.
+ * - _optionTemplate(option:SelectOption): Renders the option. To use a special widget, use its tag in render.
+ * Select option:
+ * ```js
+ * return html`
+ * `;
+ * ```
+ *
+ *
+ * or pass it off to a different WebComponent:
+ *
+ * ```js
+ * _optionTemplate(option:SelectOption) : TemplateResult
+ * {
+ * return html`
+ * `;
+ * }
+ * ```
+ *
+ * Optionally, you can override:
+ * - _emptyLabelTemplate(): How to render the empty label
+ * - slots(): Most Lion components have an input slot where the tag is created.
+ * You can specify something else, or return {} to do your own thing. This is a little more complicated. You should
+ * also override _inputGroupInputTemplate() to do what you normally would in render().
+ *
+ *
+ * Technical note:
* LionSelect (and any other LionField) use slots to wrap a real DOM node. ET2 doesn't expect this,
* so we have to create the input node (via slots()) and respect that it is _external_ to the Web Component.
* This complicates things like adding the options, since we can't just override _inputGroupInputTemplate()
@@ -65,6 +96,21 @@ export const Et2widgetWithSelectMixin = dedupeMixin((superclass) =>
{
this.set_select_options(find_select_options(this));
}
+
+ // Add in actual option tags to the DOM based on the new select_options
+ if(changedProperties.has('select_options'))
+ {
+ // Add in options as children to the target node
+ if(this._optionTargetNode)
+ {
+ // We use this.get_select_options() instead of this.select_options so children can override
+ // This is how the sub-types with static options (day of week, month, etc.) get their options in
+ render(html`${this._emptyLabelTemplate()}
+ ${repeat(this.get_select_options(), (option : SelectOption) => option.value, this._optionTemplate.bind(this))}`,
+ this._optionTargetNode
+ );
+ }
+ }
}
/**
@@ -121,19 +167,55 @@ export const Et2widgetWithSelectMixin = dedupeMixin((superclass) =>
return this.select_options;
}
+ /**
+ * Get the node where we're putting the options
+ *
+ * If this were a normal selectbox, this would be just the