From 09d5596b45d45e8401823dd88d553ff4591f0911 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 10 May 2023 22:11:27 +0300 Subject: [PATCH] fix: run validation on value change closes #4251 --- .changeset/fast-jars-protect.md | 5 +++ packages/vee-validate/src/Field.ts | 13 +------ packages/vee-validate/src/useField.ts | 13 +++---- packages/vee-validate/tests/useField.spec.ts | 38 ++++++++++++++++++++ 4 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 .changeset/fast-jars-protect.md diff --git a/.changeset/fast-jars-protect.md b/.changeset/fast-jars-protect.md new file mode 100644 index 000000000..6fc8360af --- /dev/null +++ b/.changeset/fast-jars-protect.md @@ -0,0 +1,5 @@ +--- +'vee-validate': patch +--- + +fix: run validation on value change closes #4251 diff --git a/packages/vee-validate/src/Field.ts b/packages/vee-validate/src/Field.ts index 09d144bfb..71ba5372a 100644 --- a/packages/vee-validate/src/Field.ts +++ b/packages/vee-validate/src/Field.ts @@ -147,17 +147,6 @@ const FieldImpl = defineComponent({ ctx.emit('update:modelValue', value.value); }; - const handleInput = (e: any) => { - if (!hasCheckedAttr(ctx.attrs.type)) { - value.value = normalizeEventValue(e); - } - }; - - const onInputHandler = function handleInputWithModel(e: any) { - handleInput(e); - ctx.emit('update:modelValue', value.value); - }; - const fieldProps = computed(() => { const { validateOnInput, validateOnChange, validateOnBlur, validateOnModelUpdate } = resolveValidationTriggers(props); @@ -218,7 +207,7 @@ const FieldImpl = defineComponent({ validate: validateField, resetField, handleChange: onChangeHandler, - handleInput: onInputHandler, + handleInput: e => onChangeHandler(e, false), handleReset, handleBlur, setTouched, diff --git a/packages/vee-validate/src/useField.ts b/packages/vee-validate/src/useField.ts index 660f95080..b8a5df121 100644 --- a/packages/vee-validate/src/useField.ts +++ b/packages/vee-validate/src/useField.ts @@ -218,11 +218,7 @@ function _useField( // Common input/change event handler function handleChange(e: unknown, shouldValidate = true) { const newValue = normalizeEventValue(e) as TValue; - - setValue(newValue, false); - if (!validateOnValueUpdate && shouldValidate) { - validateWithStateMutation(); - } + setValue(newValue, shouldValidate); } // Runs the initial validation @@ -257,13 +253,14 @@ function _useField( validateValidStateOnly(); } - function setValue(newValue: TValue, validate = true) { + function setValue(newValue: TValue, shouldValidate = true) { value.value = newValue; - if (!validate) { + if (!shouldValidate) { + validateValidStateOnly(); return; } - const validateFn = validateOnValueUpdate ? validateWithStateMutation : validateValidStateOnly; + const validateFn = shouldValidate ? validateWithStateMutation : validateValidStateOnly; validateFn(); } diff --git a/packages/vee-validate/tests/useField.spec.ts b/packages/vee-validate/tests/useField.spec.ts index a57ee099a..e8bfc6bfa 100644 --- a/packages/vee-validate/tests/useField.spec.ts +++ b/packages/vee-validate/tests/useField.spec.ts @@ -832,4 +832,42 @@ describe('useField()', () => { await flushPromises(); expect(name?.textContent).toBe('second'); }); + + test('handle change validates the field by default', async () => { + let field!: FieldContext; + const validator = vi.fn(val => (val ? true : REQUIRED_MESSAGE)); + mountWithHoc({ + setup() { + field = useField('field', validator); + }, + template: `
`, + }); + + await flushPromises(); + expect(validator).toHaveBeenCalledTimes(1); + expect(field.errorMessage.value).toBe(undefined); + field.handleChange(''); + await flushPromises(); + expect(field.errorMessage.value).toBe(REQUIRED_MESSAGE); + }); + + test('handle change can be configured to not validate the field', async () => { + let field!: FieldContext; + const validator = vi.fn(val => (val ? true : REQUIRED_MESSAGE)); + mountWithHoc({ + setup() { + field = useField('field', validator, { validateOnValueUpdate: false }); + }, + template: `
`, + }); + + await flushPromises(); + expect(validator).toHaveBeenCalledTimes(1); + expect(field.errorMessage.value).toBe(undefined); + field.handleChange('', false); + await flushPromises(); + + expect(validator).toHaveBeenCalledTimes(2); + expect(field.errorMessage.value).toBe(undefined); + }); });