logaretm / vee-validate

✅ Painless Vue forms
https://vee-validate.logaretm.com/v4
MIT License
10.81k stars 1.26k forks source link

Access the `Form`s `values` from a `ref` #4006

Closed BudiSalah closed 1 year ago

BudiSalah commented 1 year ago

For some reason, I was trying to set the validation-schema dynamically based on the inputs new values, I needed to access the Form values through a ref and I was expecting to find the current form values but I didn't found it. It would be nice to have this in the Form instance.

image

logaretm commented 1 year ago

How about I expose getValues that gives you the current value? or rather a copy of it. Would that work? or do you need it to be reactive? if so why not use the useForm instead?

BudiSalah commented 1 year ago

getValues would be great, also, make it reactive if possible with the readonly type. useForm is a great solution but, for the current project I'm working on with so many forms, it would be difficult to convert the existing structure to use the composition API as the current forms usually built with the components.

BudiSalah commented 1 year ago

getMeta would also be great!

mcube27 commented 1 year ago

I agree fieldMeta would be nice to be accessible from a parent. In V3 we could access fields and fields.meta from the form slot prop. I have been trying for hours to get the same in V4 and always bump into errors.

lbineau commented 1 year ago

Same need here, <Form> is very limited to be used programmatically. Getting values and meta is impossible from the parent component. This forces us to use useForm but it would mean reimplement completely the <Form> component...

For now I'm doing a workaround like like:

<script>
export default {
  name: 'VRenderless'
}
</script>

<template>
  <slot v-bind="$attrs" />
</template>
<template>
  <Form ref="form" as="" v-slot="slotProps" @invalid-submit="onInvalidSubmit">
    <!-- this component does not render anything -->
    <VRenderless :onMetaChange="onMetaChange(slotProps.meta)"/>
   </Form>
</template>
<script>
export default {
  name: 'FormContainer'
  methods: {
    onMetaChange (meta) {
       // do something about meta here
    }
  }
}
</script>

The onMetaChange is triggered by the template which feels really dirty and probably a lot unnecessary extra work. Same could apply to values I believe.

logaretm commented 1 year ago

To manage expectations here. Exposing reactive stuff via refs is not a good idea because it will only be available after mount, so your code will need to handle that possibility. It works only because of the Vue's excellent reactivity system but I always though that was a dark/bad pattern from Vue 2.x days since we had no better alternative.

$refs usage should be only limited to executing functions or accessing non-reactive stuff in callbacks and not in the template. If you want reactivity then, you need to use the composition API because that's its purpose, at least for this lib.

Higher order components have been always limited to use in the Vue's template syntax, so this isn't a new or limited to vee-validate.

Having said that, I'm working on adding getValues and getMeta and getErrors which will return non-reactive versions of these values. In the future we can work on making useForm reflect the state of a form in the template which also makes this easier in this case but that's an implementation for another time.