From 66793878e317f32f4759b3d01e27e3b9072eff67 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Wed, 2 Jun 2021 23:31:18 +0200 Subject: [PATCH] fix: respect the Field bails option closes #3332 --- packages/vee-validate/src/types.ts | 1 + packages/vee-validate/src/useField.ts | 13 ++------- packages/vee-validate/src/useForm.ts | 16 +++++++++- packages/vee-validate/src/validate.ts | 4 +-- packages/vee-validate/tests/Form.spec.ts | 37 ++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/packages/vee-validate/src/types.ts b/packages/vee-validate/src/types.ts index 612a9a3e3..b65a4294d 100644 --- a/packages/vee-validate/src/types.ts +++ b/packages/vee-validate/src/types.ts @@ -48,6 +48,7 @@ export interface PrivateFieldComposite { errorMessage: ComputedRef; label?: MaybeRef; type?: string; + bails?: boolean; checkedValue?: MaybeRef; uncheckedValue?: MaybeRef; checked?: ComputedRef; diff --git a/packages/vee-validate/src/useField.ts b/packages/vee-validate/src/useField.ts index fb0efbba4..ead79c3b5 100644 --- a/packages/vee-validate/src/useField.ts +++ b/packages/vee-validate/src/useField.ts @@ -71,16 +71,8 @@ export function useField( opts?: Partial> ): FieldComposable { const fid = ID_COUNTER >= Number.MAX_SAFE_INTEGER ? 0 : ++ID_COUNTER; - const { - initialValue, - validateOnMount, - bails, - type, - checkedValue, - label, - validateOnValueUpdate, - uncheckedValue, - } = normalizeOptions(unref(name), opts); + const { initialValue, validateOnMount, bails, type, checkedValue, label, validateOnValueUpdate, uncheckedValue } = + normalizeOptions(unref(name), opts); const form = injectWithSelf(FormContextSymbol); const { @@ -205,6 +197,7 @@ export function useField( checkedValue, uncheckedValue, checked, + bails, resetField, handleReset: () => resetField(), validate: validateWithStateMutation, diff --git a/packages/vee-validate/src/useForm.ts b/packages/vee-validate/src/useForm.ts index aebdcbbcb..5d1b734d2 100644 --- a/packages/vee-validate/src/useForm.ts +++ b/packages/vee-validate/src/useForm.ts @@ -465,6 +465,17 @@ export function useForm = Record); }); + const fieldBailsMap = computed(() => { + return keysOf(fieldsById.value).reduce((map, path) => { + const field = normalizeField(fieldsById.value[path]); + if (field) { + map[path as string] = field.bails ?? true; + } + + return map; + }, {} as Record); + }); + async function validateSchema(mode: SchemaValidationMode): Promise> { const schemaValue = unref(schema); if (!schemaValue) { @@ -473,7 +484,10 @@ export function useForm = Record, formValues, { names: fieldNames.value }); + : await validateObjectSchema(schemaValue as RawFormSchema, formValues, { + names: fieldNames.value, + bailsMap: fieldBailsMap.value, + }); // fields by id lookup const fieldsById = formCtx.fieldsById.value || {}; diff --git a/packages/vee-validate/src/validate.ts b/packages/vee-validate/src/validate.ts index 1c6b3fce9..2fc234d80 100644 --- a/packages/vee-validate/src/validate.ts +++ b/packages/vee-validate/src/validate.ts @@ -236,14 +236,14 @@ export async function validateYupSchema( export async function validateObjectSchema( schema: RawFormSchema, values: TValues, - opts?: Partial<{ names: Record; bails: boolean }> + opts?: Partial<{ names: Record; bailsMap: Record }> ): Promise> { const paths = keysOf(schema) as string[]; const validations = paths.map(async path => { const fieldResult = await validate(getFromPath(values as any, path), schema[path as keyof TValues], { name: opts?.names?.[path] || path, values: values as any, - bails: opts?.bails ?? true, + bails: opts?.bailsMap?.[path] ?? true, }); return { diff --git a/packages/vee-validate/tests/Form.spec.ts b/packages/vee-validate/tests/Form.spec.ts index f9bd18340..7429cdcfd 100644 --- a/packages/vee-validate/tests/Form.spec.ts +++ b/packages/vee-validate/tests/Form.spec.ts @@ -6,6 +6,7 @@ import { computed, onErrorCaptured, reactive, ref, Ref } from 'vue'; describe('
', () => { const REQUIRED_MESSAGE = `This field is required`; + const MIN_MESSAGE = `This field is short`; defineRule('required', (value: unknown) => { if (!value) { return REQUIRED_MESSAGE; @@ -13,6 +14,13 @@ describe('', () => { return true; }); + defineRule('min', (value: unknown, args: any[]) => { + if (!value || String(value).length <= args[0]) { + return MIN_MESSAGE; + } + + return true; + }); test('renders the as prop', () => { const wrapper = mountWithHoc({ @@ -2045,4 +2053,33 @@ describe('', () => { expect.anything() ); }); + + // #3332 + test('field bails prop should work with validation schema', async () => { + const wrapper = mountWithHoc({ + setup() { + return { + schema: { + fname: 'required|min:3', + }, + }; + }, + template: ` + + + +
+ {{ error }} +
+
+
+ `, + }); + + await flushPromises(); + const input = wrapper.$el.querySelector('input'); + setValue(input, ''); + await flushPromises(); + expect(document.querySelectorAll('.error')).toHaveLength(2); + }); });