import cx from "classnames"; import { LightningElement, api } from "lwc"; import { SelectOption } from "typings/custom"; import { toJson, normalizeBoolean } from "dxUtils/normalizers"; import { reflectBooleanAttribute } from "dxUtils/lwc"; export const DEFAULT_MISSING_MESSAGE = "This field is required"; export default class Select extends LightningElement { @api accessKey!: string; @api autocomplete?: string; @api label?: string; @api messageWhenValueMissing: string = DEFAULT_MISSING_MESSAGE; @api placeholder?: string; @api size?: string; @api loading = false; @api get disabled() { return this._disabled; } set disabled(value) { this._disabled = normalizeBoolean(value); } @api get options() { return this._options; } set options(value) { this._options = toJson(value); } @api get required() { return this._required; } set required(value) { this._required = normalizeBoolean(value); reflectBooleanAttribute( this as unknown as LightningElement, "required", value ); } @api get value() { return this._value; } set value(value) { this._value = value; this.updateSelectValue(); } @api get name() { return this._name; } set name(name) { this._name = name; this.setAttribute("name", name); // reflect to HTML } _disabled = false; _size = ""; _required = false; _options: Array = []; _value: string = ""; _name?: string; _selectElement: HTMLSelectElement | null = null; helpMessage?: string = ""; renderedCallback(): void { this.updateSelectValue(); } get containerClass() { return cx("form-element", this.hasError && "has-error"); } get hasError(): boolean { return !!this.helpMessage; } get selectClass() { return cx("select-element", { "select-element_placeholder": this.placeholder && !this.value }); } get selectElement() { if (!this._selectElement) { this._selectElement = this.template.querySelector("select"); } return this._selectElement; } get isRequiredButEmpty() { return this.required && !this.value; } @api blur(): void { if (this.selectElement) { this.selectElement.blur(); } } @api focus(): void { if (this.selectElement) { this.selectElement.focus(); } } @api reportValidity(): boolean { const isInvalid = this.isRequiredButEmpty; this.helpMessage = isInvalid ? this.messageWhenValueMissing || DEFAULT_MISSING_MESSAGE : ""; return !isInvalid; } @api checkValidity(): boolean { return !this.isRequiredButEmpty; } handleBlur(): void { this.reportValidity(); this.dispatchEvent(new CustomEvent("blur")); } handleChange(event: Event & { target: HTMLSelectElement }): void { const { value } = event.target; this._value = value; this.dispatchEvent( new CustomEvent("change", { detail: { value } }) ); } handleFocus(): void { this.helpMessage = ""; this.dispatchEvent(new CustomEvent("focus")); } // We have to do it programmatically because value binding doesn't work apparently. updateSelectValue(): void { if (!this._value && !this.placeholder) { return; } if (this.selectElement) { this.selectElement.value = this._value; } } }