From 43dd132013d0748aac96afb61460e6c48d48776b Mon Sep 17 00:00:00 2001 From: Konstantinos Norgias Date: Tue, 19 Apr 2022 10:27:38 +0200 Subject: [PATCH] fix: do not show ResultValidator feedback message if input field is empty --- .changeset/tender-otters-shake.md | 5 +++ docs/components/form/use-cases.md | 1 - .../form-core/src/validate/ValidateMixin.js | 18 ++++++-- .../ValidateMixinFeedbackPart.suite.js | 41 ++++++++++++++++++- 4 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 .changeset/tender-otters-shake.md diff --git a/.changeset/tender-otters-shake.md b/.changeset/tender-otters-shake.md new file mode 100644 index 000000000..303ecd829 --- /dev/null +++ b/.changeset/tender-otters-shake.md @@ -0,0 +1,5 @@ +--- +'@lion/form-core': patch +--- + +fix: reset the form validators after a form `reset` click or field emptied diff --git a/docs/components/form/use-cases.md b/docs/components/form/use-cases.md index 246277ec8..4c3d706ee 100644 --- a/docs/components/form/use-cases.md +++ b/docs/components/form/use-cases.md @@ -23,7 +23,6 @@ To fire a submit from JavaScript, select the `lion-form` element and call `.subm ```js preview-story export const formSubmit = () => { loadDefaultFeedbackMessages(); - const submitHandler = ev => { if (ev.target.hasFeedbackFor.includes('error')) { const firstFormElWithError = ev.target.formElements.find(el => diff --git a/packages/form-core/src/validate/ValidateMixin.js b/packages/form-core/src/validate/ValidateMixin.js index 41c6b5fad..1a314d8d1 100644 --- a/packages/form-core/src/validate/ValidateMixin.js +++ b/packages/form-core/src/validate/ValidateMixin.js @@ -499,7 +499,7 @@ export const ValidateMixinImplementation = superclass => /** * step b (as explained in `validate()`), called by __finishValidation - * @param {{validator:Validator; outcome: boolean|string;}[]} regularValidationResult result of steps 1-3 + * @param {{validator: Validator;outcome: boolean | string;}[]} regularValidationResult result of steps 1-3 * @private */ __executeResultValidators(regularValidationResult) { @@ -510,6 +510,16 @@ export const ValidateMixinImplementation = superclass => }) ); + if (!resultValidators.length) { + return []; + } + + // If empty, do not show the ResulValidation message (e.g. Correct!) + if (this._isEmpty(this.modelValue)) { + this.__prevShownValidationResult = []; + return []; + } + // Map everything to Validator[] for backwards compatibility return resultValidators .map(v => ({ @@ -537,8 +547,9 @@ export const ValidateMixinImplementation = superclass => __finishValidation({ source, hasAsync }) { const syncAndAsyncOutcome = [...this.__syncValidationResult, ...this.__asyncValidationResult]; // if we have any ResultValidators left, now is the time to run them... - const resultOutCome = this.__executeResultValidators(syncAndAsyncOutcome); - + const resultOutCome = /** @type {ValidationResultEntry[]} */ ( + this.__executeResultValidators(syncAndAsyncOutcome) + ); this.__validationResult = [...resultOutCome, ...syncAndAsyncOutcome]; const ctor = /** @type {ValidateHostConstructor} */ (this.constructor); @@ -560,7 +571,6 @@ export const ValidateMixinImplementation = superclass => this.hasFeedbackFor = [ ...new Set(this.__validationResult.map(({ validator }) => validator.type)), ]; - /** private event that should be listened to by LionFieldSet */ this.dispatchEvent(new Event('validate-performed', { bubbles: true })); if (source === 'async' || !hasAsync) { diff --git a/packages/form-core/test-suites/ValidateMixinFeedbackPart.suite.js b/packages/form-core/test-suites/ValidateMixinFeedbackPart.suite.js index f9f8dce01..6fcc86478 100644 --- a/packages/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +++ b/packages/form-core/test-suites/ValidateMixinFeedbackPart.suite.js @@ -4,7 +4,14 @@ import { localizeTearDown } from '@lion/localize/test-helpers'; import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import { getFormControlMembers } from '@lion/form-core/test-helpers'; import sinon from 'sinon'; -import { DefaultSuccess, MinLength, Required, ValidateMixin, Validator } from '../index.js'; +import { + DefaultSuccess, + MinLength, + MaxLength, + Required, + ValidateMixin, + Validator, +} from '../index.js'; import { AlwaysInvalid } from '../test-helpers/index.js'; /** @@ -373,6 +380,38 @@ export function runValidateMixinFeedbackPart() { expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message'); }); + it('does not show success message after fixing error an & field is empty', async () => { + class ValidateElementCustomTypes extends ValidateMixin(LitElement) { + static get validationTypes() { + return ['error', 'success']; + } + } + const elTagString = defineCE(ValidateElementCustomTypes); + const elTag = unsafeStatic(elTagString); + const el = /** @type {ValidateElementCustomTypes} */ ( + await fixture(html` + <${elTag} + .submitted=${true} + .validators=${[ + new MaxLength(3, { getMessage: async () => 'Max length is 3!' }), + new DefaultSuccess(null, { getMessage: () => 'This is a success message' }), + ]} + >${lightDom} + `) + ); + const { _feedbackNode } = getFormControlMembers(el); + + el.modelValue = 'abcd'; + await el.updateComplete; + await el.feedbackComplete; + expect(_feedbackNode.feedbackData?.[0].message).to.equal('Max length is 3!'); + + el.modelValue = ''; + await el.updateComplete; + await el.feedbackComplete; + expect(_feedbackNode.feedbackData).to.deep.equal([]); + }); + describe('Accessibility', () => { it('sets [aria-invalid="true"] to "._inputNode" when there is an error', async () => { const el = /** @type {ValidateElement} */ (