Hide server-side validation messages while widget has focus. If the value did not change, put messages back

This commit is contained in:
nathan 2023-01-09 16:02:59 -07:00
parent ffb26cb2f1
commit 1163f9e31d
2 changed files with 77 additions and 15 deletions

View File

@ -56,6 +56,8 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
protected defaultValidators : Validator[]; protected defaultValidators : Validator[];
// Promise used during validation // Promise used during validation
protected validateComplete : Promise<undefined>; protected validateComplete : Promise<undefined>;
// Hold on to any server messages while the user edits
private _messagesHeldWhileFocused : Validator[];
protected isSlComponent = false; protected isSlComponent = false;
@ -66,16 +68,19 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
...super.styles, ...super.styles,
css` css`
/* Allow actually disabled inputs */ /* Allow actually disabled inputs */
:host([disabled]) { :host([disabled]) {
display: initial; display: initial;
} }
/* Needed so required can show through */ /* Needed so required can show through */
::slotted(input), input { ::slotted(input), input {
background-color: transparent; background-color: transparent;
} }
/* Used to allow auto-sizing on slotted inputs */ /* Used to allow auto-sizing on slotted inputs */
.input-group__container > .input-group__input ::slotted(.form-control) { .input-group__container > .input-group__input ::slotted(.form-control) {
width: 100%; width: 100%;
} }
@ -162,10 +167,14 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
this.validators = []; this.validators = [];
this.defaultValidators = []; this.defaultValidators = [];
this._messagesHeldWhileFocused = [];
this.__readonly = false; this.__readonly = false;
this.isSlComponent = typeof (<any>this).handleChange === 'function'; this.isSlComponent = typeof (<any>this).handleChange === 'function';
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
} }
connectedCallback() connectedCallback()
@ -177,12 +186,17 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
{ {
this.addEventListener(this.isSlComponent ? 'sl-change' : 'change', this._oldChange); this.addEventListener(this.isSlComponent ? 'sl-change' : 'change', this._oldChange);
}); });
this.addEventListener("focus", this.handleFocus);
this.addEventListener("blur", this.handleBlur);
} }
disconnectedCallback() disconnectedCallback()
{ {
super.disconnectedCallback(); super.disconnectedCallback();
this.removeEventListener(this.isSlComponent ? 'sl-change' : 'change', this._oldChange); this.removeEventListener(this.isSlComponent ? 'sl-change' : 'change', this._oldChange);
this.removeEventListener("focus", this.handleFocus);
this.removeEventListener("blur", this.handleBlur);
} }
/** /**
@ -236,6 +250,41 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
return true; return true;
} }
/**
* When input receives focus, clear any validation errors.
*
* If the value is the same on blur, we'll put them back
* The ones from the server (ManualMessage) can interfere with submitting.
* @param {FocusEvent} _ev
*/
handleFocus(_ev : FocusEvent)
{
if(this._messagesHeldWhileFocused.length > 0)
{
return;
}
this._oldValue = this.value;
// Collect any ManualMessages
this._messagesHeldWhileFocused = (this.validators || []).filter((validator) => (validator instanceof ManualMessage));
this.set_validation_error(false);
}
/**
* If the value is unchanged, put any held validation messages back
* @param {FocusEvent} _ev
*/
handleBlur(_ev : FocusEvent)
{
if(this._messagesHeldWhileFocused.length > 0 && this.value == this._oldValue)
{
this.validators = this.validators.concat(this._messagesHeldWhileFocused);
this._messagesHeldWhileFocused = [];
this.validate();
}
}
set_value(new_value) set_value(new_value)
{ {
this.value = new_value; this.value = new_value;

View File

@ -402,6 +402,19 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
<sl-menu-item value="">${this.emptyLabel}</sl-menu-item>`; <sl-menu-item value="">${this.emptyLabel}</sl-menu-item>`;
} }
/**
* Override Et2InputWidget blur handler to avoid doing our blur stuff when internal controls blur
*
* @param {FocusEvent} ev
*/
handleBlur(ev : FocusEvent)
{
if(ev.target == this)
{
super.handleBlur(ev);
}
}
/** /**
* Tag used for rendering options * Tag used for rendering options
* Used for finding & filtering options, they're created by the mixed-in class * Used for finding & filtering options, they're created by the mixed-in class