Home > Mobile >  Composition API custom input element doesn't update the value
Composition API custom input element doesn't update the value

Time:11-19

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 };
  },

CodePudding user response:

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, e.g. 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"
      
      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>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related