vee-validate
vee-validate copied to clipboard
Expose useFormContext composable
Is your feature request related to a problem? Please describe.
In cases where multiple form context elements are required, such as utility functions to manage state of reset/submit buttons depending on several factors within form context, it would be nice to have access to the form context via a composable.
For example, consider a sample function that checks whether a cancel button should be disabled or not. It checks multiple aspects of form context, which would be annoying to both get and pass in individually every time this is used 🤷. Instead, passing in FormContext allows calling the function and directly passing form context for ease of use.
/**
* Disable cancel buttons when form is submitting or empty/unsubmitted
*
* @param form - Form state (potentially from injected reference)
* @param allowWhenEmpty - Allow cancelling (reset) when empty/unsubmitted (useful in dialogs, etc)
*/
export const shouldDisableCancel = (form: FormContext<FieldValues>, allowWhenEmpty = false) => {
const isSubmittingOrValidating = form.isSubmitting.value || form.isValidating.value;
// Some locations may allow cancelling when empty/unsubmitted (ie. dialogs)
if (allowWhenEmpty) return isSubmittingOrValidating;
// Must include submit count to allow resetting field after invalid submission attempt
return isSubmittingOrValidating || (!form.meta.value.dirty && !form.submitCount.value);
};
Describe the solution you'd like
Expose a useFormContext hook to provide access to a wider array of values from within form context.
Describe alternatives you've considered
This can certainly be done by injecting the form context; however, this is not documented (perhaps intentially) except a brief reference under testing documentation. Additionally, it would be nice to expose this in the same manner as other similar composables (such as useFormValues, etc.
const formContext = inject<FormContext | undefined>(FormContextKey);
A workaround would be something like this. The problem is that the provided values by useForm is marked as readonly. If the values field (internally) from formCtx (PrivateFormContext) would be named differently, this would be possible.
This is possible because vee-validate shrinks only the type from PrivateFormContext to FormContext in reality it spreads entire private form context into the form context
https://github.com/logaretm/vee-validate/blob/926170d07bb201dbb220d0276cfc123ab2c4fbd7/packages/vee-validate/src/useForm.ts#L1200-L1205
<script setup>
const form = useForm();
const onSubmit = form.handleSubmit((values) => {});
</script>
<template>
<FormContextProvider :form="form">
<form @submit="onSubmit">
<!-- ... -->
<Field />
</form>
</FormContextProvider>
</template>
form-context.ts
export function usePrivateFormContext(form: FormContext): PrivateFormContext {
const { handleReset, submitForm, ...formCtx } = form;
return form as PrivateFormContext;
}
export const FormContextProvider = defineComponent({
props: {
form: {
type: Object as PropType<FormContext>,
required: true,
},
},
setup: (props, ctx) => {
const privateForm = usePrivateFormContext(props.form);
provide(FormContextKey, privateForm);
return () => ctx.slots.default?.();
},
});