javascriptvue.jsvuejs3emit

Vue 3 - Emitting primitive value doesn't trigger input?


I faced an strange issue with Vue3 $emit. I was refactoring my own Vue2 "form-input" -component, which is basically an wrapper for rendering either text-input, (multi)select-option, textarea or any other basic input field.

This component used to bind value against v-model, so it was emitting input via "this.$emit('input', this.value)".

Since Vue 3 changed input to update:modelValue, I made this modification and additionally presented "Emits" -property-list to component. Everything was seemingly working...

But then I recognized that Vue-multiselect 3 (NPM package "vue-multiselect": "^3.0.0-alpha.2") was emitting primitive value, an integer number, which didn't trigger @input on parent-component.

form-input.vue

<input v-if="resolveType === 'text' || resolveType === 'number' || resolveType === 'tel' || resolveType === 'email'"
             v-model="localValue"
             @input="$emit('update:modelValue', $event.target.value)"
/>

<multiselect v-model="localValue"
             class="full-width-tags"
             @update:model-value="$emit('update:modelValue', $event)"
/>

// Please note that multiselects $event is an integer, I have checked this multiple times from console.log

... and when I'm listening for @input on parent component it seems "text"-type field triggers event-listener but multiselect doesn't. Only difference on these components is that multiselect is emitting primitive value (integer), while input is sending an event-object.

Could someone explain why event-object and primitive value are handled differently for @input , and how could I fix my multiselects emit so that it's emitting input? Currently I'm emitting both "update:modelValue" AND "input" -events one after another for multiselect, but I'm just wondering if there is easier way?


Solution

  • From your question it seems you have read the Vue 3 Migration Guide - particularly the part about change of v-model on custom components and changed your form-input to emit update:modelValue event instead of input event

    So why are you listening for updates on your form-input component with @input instead of @update:modelValue ?

    The only reason why the @input placed on your form-input component in the parent works, is because of this change

    In short - because your component declares that it emits update:modelValue event (using emits option), every other event listener placed on it is directly bound to the root element of the component - native <input> in this case

    This is not what you want. Just change <form-input @input="..." /> to <form-input @update:modelValue="..." />