diff --git a/packages/vee-validate/src/index.ts b/packages/vee-validate/src/index.ts index a936bead7..f4e12b10e 100644 --- a/packages/vee-validate/src/index.ts +++ b/packages/vee-validate/src/index.ts @@ -7,6 +7,7 @@ export { Form } from './Form'; export { FieldArray } from './FieldArray'; export { ErrorMessage } from './ErrorMessage'; export { useField, FieldOptions, RuleExpression } from './useField'; +export { useFieldRef } from './useFieldRef'; export { useForm, FormOptions } from './useForm'; export { useFieldArray } from './useFieldArray'; export * from './types'; diff --git a/packages/vee-validate/src/useFieldRef.ts b/packages/vee-validate/src/useFieldRef.ts new file mode 100644 index 000000000..5cb36767e --- /dev/null +++ b/packages/vee-validate/src/useFieldRef.ts @@ -0,0 +1,75 @@ +import { MaybeRefOrGetter, MaybeRef, ref, watch, onMounted, onBeforeUnmount, Ref } from 'vue'; +import { FieldOptions, RuleExpression, useField } from './useField'; +import { getConfig } from './config'; + +interface ListenerOptions { + validateOnChange: boolean; + validateOnInput: boolean; + validateOnBlur: boolean; +} + +export function useFieldRef( + path: MaybeRefOrGetter, + rules?: MaybeRef>, + opts?: Partial & ListenerOptions>, +) { + const field = useField(path, rules, opts); + const inputRef = ref(); + + watch(field.errorMessage, msg => { + inputRef.value?.setCustomValidity(msg || ''); + }); + + watch(field.value, value => { + if (!inputRef.value) { + return; + } + + if (field.value.value === inputRef.value.value) { + return; + } + + inputRef.value.value = String(value); + }); + + useEventListener(inputRef, 'input', event => { + field.handleChange(event, opts?.validateOnInput ?? getConfig().validateOnInput); + }); + + useEventListener(inputRef, 'change', event => { + field.handleChange(event, opts?.validateOnChange ?? getConfig().validateOnChange); + }); + + useEventListener(inputRef, 'blur', event => { + field.handleBlur(event, opts?.validateOnBlur ?? getConfig().validateOnBlur); + }); + + onMounted(() => { + if (!inputRef.value) { + return; + } + + if (field.meta.required) { + inputRef.value.required = field.meta.required; + } + }); + + return { + ...field, + inputRef, + }; +} + +function useEventListener( + el: Ref, + event: string, + handler: EventListenerOrEventListenerObject, +) { + onMounted(() => { + el.value?.addEventListener(event, handler); + }); + + onBeforeUnmount(() => { + el.value?.removeEventListener(event, handler); + }); +}