简体   繁体   中英

Composition API custom input element doesn't update the value

I'm trying to create custom Input component with composition API in Vue 3 but when I'm trying to update value with v-model I am getting empty string instead of event value and when I replace custom Input component with default HTML input the value is being updated as expected

Input component:

<template>
  <input
    :type="type"
    :id="name"
    :name="name"
    :placeholder="placeholder"
    class="input"
    v-model="modelValue"
  />
</template>

<script lang="ts">
import { computed } from 'vue';

export default {
  name: 'Input',
  props: {
    modelValue: {
      type: String,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
    type: {
      type: String,
      default: 'text',
    },
    placeholder: {
      type: String,
      required: true,
    },
  },
  setup(props: { value: string }, { emit }) {
    const modelValue = computed({
      get() {
        return props.modelValue;
      },
      set(value) {
        emit('input', value);
      },
    });

    return { modelValue };
  },
};
</script>
<form @submit.prevent="handleSubmit">
     <Input :name="name" placeholder="Name*" v-model="name" />
     <Button>Send</Button>
</form>

Setup method:

  setup() {
    const name = ref('');

    function handleSubmit(data: Event) {
      console.log(data, name.value);
    }

    watch(name, (old, newValue) => {
      console.log(name, old, newValue);
    });

    return { name, handleSubmit };
  },

There are a couple of errors & warnings in your code:

  • you should declare emitted events in the emits option ( more on this here )
  • you did not have a value prop passed down from the parent component to Input (thus I removed it)
  • if you want to do the "easy sync" with v-model , then it's best to emit a custom event called update:modelValue (where modelValue is the value you want to bind as prop, eg update:name ; more on this here )
  • you should NOT name a variable in the setup function the same as a prop (this is just sensibility - you'll mess up what is what, eventually)

 const { computed, ref, } = Vue const Input = { name: 'Input', props: { name: { type: String, required: true, }, type: { type: String, default: 'text', }, placeholder: { type: String, required: true, }, }, emits: ['update:name'], setup(props, { emit }) { const modelValue = computed({ get() { return props.name; }, set(value) { emit('update:name', value); }, }); return { modelValue }; }, template: ` <input:type="type":id="name":name="name":placeholder="placeholder" class="input" v-model="modelValue" /> ` } const App = { setup() { const name = ref(''); function handleSubmit(data) { console.log(data, name.value); } return { name, handleSubmit }; }, template: ` Name Ref: {{ name }}<br /> <form @submit.prevent="handleSubmit"> <Input:name="name" placeholder="Name*" v-model="name" /> <button type="submit">Send</button> </form> ` } const vm = Vue.createApp(App) vm.component('Input', Input) vm.mount('#app')
 <script src="https://unpkg.com/vue@next"></script> <div id="app"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM