logaretm / vee-validate

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

Field component is listening to @input / @change even when v-bind is not used #3614

Closed lk77 closed 2 years ago

lk77 commented 2 years ago

What happened?

Hello,

Field component is listening to @change and @input event by default (without v-bind) and there is no way to disable this behaviour it seems, this trigger an @update:modelValue event automatically

i've added @change.stop="" @input.stop="" to prevent vee-validate to pick it up, because i use v-model instead, and i don't want native events to modify values of my forms. But it bothers me to put that on every custom component out there, and even native selects / input in some scenarios (like sub Field)

i've used validateOnBlur / validateOnChange / validateOnInput but it only disable validation, it does not prevent value override from native events

In my app, i have scenarios where value is retained until user click on an apply button, or modelValue differ from native input value for some reason, like a FieldArray, modelValue will be the whole array, but input value will be the last entry, which overrides the array by a string.

And also any @change/@input event will trigger the @update:modelValue, no matter the name of the input/select that triggered the event, custom components sometimes have multiple select/input within them, for example a single Field component with multiple input radio + a select for each radio, within the slot

thanks.

Reproduction steps

1/ Add a Form 2/ Add a Field with a custom component in the slot 3/ Do not set a v-model/v-bind or :value/@update:modelValue on the custom component 4/ See that native events still trigger @update:modelValue on when modifiying input inside custom component 5/ Add @change.stop="" @input.stop="" and see that @update:modelValue is not triggered anymore on

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

Relevant log output

No response

Demo link

https://jsfiddle.net/lk77/kqa3fsL7/19/

Code of Conduct

logaretm commented 2 years ago

This is intended, vee-validate needs to set up its own value tracking and keep track of values in real time. So this is not an issue.

You have a few ways around this:

<Field name="abc" v-slot="{ handleChange }"  :validateOnInput="false">
    <input />
    <button type="button" @click="handleChange('realValue')">handleChange</button>
</Field>
lk77 commented 2 years ago

ok, this works, the select does not override the value of the radio button anymore, that's an unexpected side effect of the as prop

i think the Field component still needs to prevent input / change events to bubble up

i dont know if that kind of structure is supported :

<Field>
   <ui-radio>
       <Field>
           <ui-select></ui-select>
       </Field>
   </ui-radio>
</Field>

Capture d’écran du 2021-12-09 09-24-45

G-Rath commented 4 months ago

fwiw I've just run across this - regardless of opinions about if it should be the default behaviour or not, what was more frustrating is that it seems to run contrary to the documentation (or at least a possible interpretation of it).

As far as I can tell, this is the closest the documentation comes to outright saying this behaviour:

The most crucial part of rendering fields with v-slot is that you bind the field object to your input element/input, the field object contains all the common attributes and listeners required for the field to be validated, this is done automatically if you are using the as prop.

This could just be because I'm relatively new to Vue + vee-validate, but my interpretation is "this is done automatically if you are using the as prop" is meaning "if you use as to render an input", especially since the start of the paragraph is saying that the most crucial part of rendering fields when using slots is that I do the binding.

My use-case is I'm upgrading an inherited application to Vue 3 and I need an element root for <transition> elements, so I've been using as="span" to maintain the old DOM structure during the upgrade and then was going to revisit better leveraging the new goodness of the vee-validate v4+ APIs post-upgrade.

So far this has been working fine until I got to our date picker component which was very confusing because it had multiple "input" types elements/components...

All in all, I think I've got myself unblocked now in part thanks to this issue (and I'm pretty sure I can make transition happy by just explicitly defining a dedicated span in my components rather than via vee-validate), though I would recommend updating the documentation to make this a bit clearer; personally I'd also prefer some prop to be able to opt-out explicitly of this "magic" for peace of mind, but I can understand if that is going against the spirit of this library/component 🙂