Skip to content

Commit

Permalink
feat(#4117): add resetField on Form/useForm (#4120)
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Feb 5, 2023
1 parent 83c2e17 commit 87c4278
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 5 deletions.
5 changes: 5 additions & 0 deletions packages/vee-validate/src/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type FormSlotProps = UnwrapRef<
| 'setFieldTouched'
| 'setTouched'
| 'resetForm'
| 'resetField'
| 'controlledValues'
>
> & {
Expand Down Expand Up @@ -93,6 +94,7 @@ const FormImpl = defineComponent({
setValues,
setFieldTouched,
setTouched,
resetField,
} = useForm({
validationSchema: validationSchema.value ? validationSchema : undefined,
initialValues,
Expand Down Expand Up @@ -147,6 +149,7 @@ const FormImpl = defineComponent({
setFieldTouched,
setTouched,
resetForm,
resetField,
};
}

Expand All @@ -161,6 +164,7 @@ const FormImpl = defineComponent({
resetForm,
validate,
validateField,
resetField,
});

return function renderForm() {
Expand Down Expand Up @@ -204,6 +208,7 @@ export const Form = FormImpl as typeof FormImpl & {
setFieldTouched: FormContext['setFieldTouched'];
setTouched: FormContext['setTouched'];
resetForm: FormContext['resetForm'];
resetField: FormContext['resetField'];
validate: FormContext['validate'];
validateField: FormContext['validateField'];
$slots: {
Expand Down
11 changes: 6 additions & 5 deletions packages/vee-validate/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@ export interface SetFieldValueOptions {
}
export interface FormActions<TValues extends GenericFormValues> {
setFieldValue<T extends keyof TValues>(field: T, value: TValues[T], opts?: Partial<SetFieldValueOptions>): void;
setFieldError: (field: keyof TValues, message: string | string[] | undefined) => void;
setErrors: (fields: FormErrors<TValues>) => void;
setFieldError(field: keyof TValues, message: string | string[] | undefined): void;
setErrors(fields: FormErrors<TValues>): void;
setValues<T extends keyof TValues>(fields: Partial<Record<T, TValues[T]>>): void;
setFieldTouched: (field: keyof TValues, isTouched: boolean) => void;
setTouched: (fields: Partial<Record<keyof TValues, boolean>>) => void;
resetForm: (state?: Partial<FormState<TValues>>) => void;
setFieldTouched(field: keyof TValues, isTouched: boolean): void;
setTouched(fields: Partial<Record<keyof TValues, boolean>>): void;
resetForm(state?: Partial<FormState<TValues>>): void;
resetField(field: keyof TValues, state?: Partial<FieldState>): void;
}

export interface FormValidationResult<TValues> {
Expand Down
11 changes: 11 additions & 0 deletions packages/vee-validate/src/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
PrivateFieldArrayContext,
InvalidSubmissionHandler,
MapValues,
FieldState,
} from './types';
import {
getFromPath,
Expand Down Expand Up @@ -270,6 +271,7 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
setValues,
setFieldValue,
resetForm,
resetField,
});
}

Expand Down Expand Up @@ -329,6 +331,7 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
setFieldTouched,
setTouched,
resetForm,
resetField,
handleSubmit,
stageInitialValue,
unsetInitialValue,
Expand Down Expand Up @@ -486,6 +489,14 @@ export function useForm<TValues extends Record<string, any> = Record<string, any
});
}

function resetField(field: keyof TValues, state?: Partial<FieldState>) {
const fieldInstance = fieldsByPath.value[field];

if (fieldInstance) {
applyFieldMutation(fieldInstance, f => f.resetField(state));
}
}

/**
* Resets all fields
*/
Expand Down
68 changes: 68 additions & 0 deletions packages/vee-validate/tests/Form.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2760,6 +2760,74 @@ describe('<Form />', () => {
await flushPromises();
expect(value.value).toBe(true);
});

test('resets a single field resetField() to initial state in slot scope props', async () => {
const wrapper = mountWithHoc({
template: `
<VForm v-slot="{ resetField }">
<Field name="field" rules="required" v-slot="{ field, errors, meta }">
<input type="text" v-bind="field">
<span id="error">{{ errors && errors[0] }}</span>
<span id="touched">{{ meta.touched }}</span>
<button @click="resetField('field')" type="button">Reset</button>
</Field>
</VForm>
`,
});

const error = wrapper.$el.querySelector('#error');
const touched = wrapper.$el.querySelector('#touched');
const input = wrapper.$el.querySelector('input');

expect(error.textContent).toBe('');

setValue(input, '');
await flushPromises();
expect(error.textContent).toBe(REQUIRED_MESSAGE);
setValue(input, '123');
dispatchEvent(input, 'blur');
await flushPromises();
expect(touched.textContent).toBe('true');
wrapper.$el.querySelector('button').click();
await flushPromises();
expect(error.textContent).toBe('');
expect(input.value).toBe('');
expect(touched.textContent).toBe('false');
});

test('resets a single field resetField() to specific state in slot scope props', async () => {
const wrapper = mountWithHoc({
template: `
<VForm v-slot="{ resetField }">
<Field name="field" rules="required" v-slot="{ field, errors, meta }">
<input type="text" v-bind="field">
<span id="error">{{ errors && errors[0] }}</span>
<span id="touched">{{ meta.touched }}</span>
<button @click="resetField('field', { value: 'test', touched: true })" type="button">Reset</button>
</Field>
</VForm>
`,
});

const error = wrapper.$el.querySelector('#error');
const touched = wrapper.$el.querySelector('#touched');
const input = wrapper.$el.querySelector('input');

expect(error.textContent).toBe('');

setValue(input, '');
await flushPromises();
expect(error.textContent).toBe(REQUIRED_MESSAGE);
setValue(input, '123');
dispatchEvent(input, 'blur');
await flushPromises();
expect(touched.textContent).toBe('true');
wrapper.$el.querySelector('button').click();
await flushPromises();
expect(error.textContent).toBe('');
expect(input.value).toBe('test');
expect(touched.textContent).toBe('true');
});
});

// #3963
Expand Down

0 comments on commit 87c4278

Please sign in to comment.