diff --git a/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts b/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts index c765caab05..87b3855904 100644 --- a/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts +++ b/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts @@ -54,6 +54,8 @@ const Et2InputWidgetMixin = >(superclass : T) protected validators : Validator[]; // Validators for every instance of a type of widget protected defaultValidators : Validator[]; + // Promise used during validation + protected validateComplete : Promise; protected isSlComponent = false; @@ -426,25 +428,31 @@ const Et2InputWidgetMixin = >(superclass : T) values.forEach((value) => doCheck(value, validator)); } }); - await Promise.all(resultPromises); + this.validateComplete = Promise.all(resultPromises); - // Show feedback from all failing validators - if(feedbackData.length > 0) + // Wait until all validation is finished, then update UI + this.validateComplete.then(() => { - let feedback = document.createElement("lion-validation-feedback"); - feedback.feedbackData = feedbackData; - feedback.slot = "help-text"; - this.append(feedback); - if(this.shadowRoot.querySelector("slot[name='feedback']")) + // Show feedback from all failing validators + if(feedbackData.length > 0) { - feedback.slot = "feedback"; + let feedback = document.createElement("lion-validation-feedback"); + feedback.feedbackData = feedbackData; + feedback.slot = "help-text"; + this.append(feedback); + if(this.shadowRoot.querySelector("slot[name='feedback']")) + { + feedback.slot = "feedback"; + } + else + { + // Not always visible? + (this.shadowRoot.querySelector("#help-text")).style.display = "initial"; + } } - else - { - // Not always visible? - (this.shadowRoot.querySelector("#help-text")).style.display = "initial"; - } - } + }); + + return this.validateComplete; } set_validation_error(err : string | false) @@ -482,6 +490,17 @@ const Et2InputWidgetMixin = >(superclass : T) this.validate(); } + /** + * Get a list of feedback types + * + * @returns {string[]} + */ + public get hasFeedbackFor() : string[] + { + let feedback = (this.querySelector("lion-validation-feedback"))?.feedbackData || []; + return feedback.map((f) => f.type); + } + /** * Called whenever the template gets submitted. We return false if the widget * is not valid, which cancels the submission. diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index 9c29a91043..c49fd85bb6 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -1086,14 +1086,18 @@ export class etemplate2 { let invalid_widgets = widgets.filter((widget) => widget); - if(invalid_widgets.length) + if(invalid_widgets.length && !(invalid_widgets[0] instanceof et2_widget)) { - // Show the first invalid widget, not the last - if(invalid_widgets[0] && invalid_widgets[0] instanceof et2_widget) + // Handle validation_error (messages coming back from server as a response) if widget is children of a tabbox + let tmpWidget = invalid_widgets[0]; + while(tmpWidget.getParent() && tmpWidget.getType() !== 'ET2-TABBOX') { - let messages = []; - let valid = invalid_widgets[0].isValid(messages); - invalid_widgets[0].set_validation_error(messages); + tmpWidget = tmpWidget.getParent(); + } + //Activate the tab where the widget with validation error is located + if(tmpWidget.getType() === 'ET2-TABBOX') + { + (tmpWidget).activateTab(invalid_widgets[0]); } } else