Skip to content

Commit

Permalink
fix: respect the Field bails option closes #3332
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Jun 2, 2021
1 parent 53ce6ec commit 6679387
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
1 change: 1 addition & 0 deletions packages/vee-validate/src/types.ts
Expand Up @@ -48,6 +48,7 @@ export interface PrivateFieldComposite<TValue = unknown> {
errorMessage: ComputedRef<string | undefined>;
label?: MaybeRef<string | undefined>;
type?: string;
bails?: boolean;
checkedValue?: MaybeRef<TValue>;
uncheckedValue?: MaybeRef<TValue>;
checked?: ComputedRef<boolean>;
Expand Down
13 changes: 3 additions & 10 deletions packages/vee-validate/src/useField.ts
Expand Up @@ -71,16 +71,8 @@ export function useField<TValue = unknown>(
opts?: Partial<FieldOptions<TValue>>
): FieldComposable<TValue> {
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 {
Expand Down Expand Up @@ -205,6 +197,7 @@ export function useField<TValue = unknown>(
checkedValue,
uncheckedValue,
checked,
bails,
resetField,
handleReset: () => resetField(),
validate: validateWithStateMutation,
Expand Down
16 changes: 15 additions & 1 deletion packages/vee-validate/src/useForm.ts
Expand Up @@ -465,6 +465,17 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
}, {} as Record<string, string>);
});

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<string, boolean>);
});

async function validateSchema(mode: SchemaValidationMode): Promise<FormValidationResult<TValues>> {
const schemaValue = unref(schema);
if (!schemaValue) {
Expand All @@ -473,7 +484,10 @@ export function useForm<TValues extends Record<string, any> = Record<string, any

const formResult = isYupValidator(schemaValue)
? await validateYupSchema(schemaValue, formValues)
: await validateObjectSchema(schemaValue as RawFormSchema<TValues>, formValues, { names: fieldNames.value });
: await validateObjectSchema(schemaValue as RawFormSchema<TValues>, formValues, {
names: fieldNames.value,
bailsMap: fieldBailsMap.value,
});

// fields by id lookup
const fieldsById = formCtx.fieldsById.value || {};
Expand Down
4 changes: 2 additions & 2 deletions packages/vee-validate/src/validate.ts
Expand Up @@ -236,14 +236,14 @@ export async function validateYupSchema<TValues>(
export async function validateObjectSchema<TValues>(
schema: RawFormSchema<TValues>,
values: TValues,
opts?: Partial<{ names: Record<string, string>; bails: boolean }>
opts?: Partial<{ names: Record<string, string>; bailsMap: Record<string, boolean> }>
): Promise<FormValidationResult<TValues>> {
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 {
Expand Down
37 changes: 37 additions & 0 deletions packages/vee-validate/tests/Form.spec.ts
Expand Up @@ -6,13 +6,21 @@ import { computed, onErrorCaptured, reactive, ref, Ref } from 'vue';

describe('<Form />', () => {
const REQUIRED_MESSAGE = `This field is required`;
const MIN_MESSAGE = `This field is short`;
defineRule('required', (value: unknown) => {
if (!value) {
return REQUIRED_MESSAGE;
}

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({
Expand Down Expand Up @@ -2045,4 +2053,33 @@ describe('<Form />', () => {
expect.anything()
);
});

// #3332
test('field bails prop should work with validation schema', async () => {
const wrapper = mountWithHoc({
setup() {
return {
schema: {
fname: 'required|min:3',
},
};
},
template: `
<VForm :validation-schema="schema">
<Field name="fname" :bails="false" v-slot="{ field, errors }">
<input type="text" v-bind="field" />
<div v-for="error in errors" :key="error" class="error">
{{ error }}
</div>
</Field>
</VForm>
`,
});

await flushPromises();
const input = wrapper.$el.querySelector('input');
setValue(input, '');
await flushPromises();
expect(document.querySelectorAll('.error')).toHaveLength(2);
});
});

0 comments on commit 6679387

Please sign in to comment.