Home > Mobile >  Why is my Input component not being able to be reactive trough v-model?
Why is my Input component not being able to be reactive trough v-model?

Time:06-23

I'm quite new with Vue, and I'm trying to make a simple Input as reusable as possible, the props are working well, but it's not being reactive, and I don't understand why. For what I heard, in order to make a component v-model allowed it should

  • first have a prop called: modelValue tied as :value="modelValue"
  • And in second instance it should $emit() an event.

I'm doing both of them, and I'm not getting any reactive behavior, so here's my code: Input-Child Component:

<template>
  <div >
    <label for="base-input">{{ label }}</label>
    <input
      
      :placeholder="placeholder"
      :value="modelValue"
      @input="$emit('customChange:modelValue', $event.target.value)"
      v-bind="$attrs"
      id="base-input"
    />
  </div>
</template>

<script>
export default {
  name: "BaseInput",
  props: {
    label: {
      type: String,
    },
    placeholder: {
      type: String,
    },
    modelValue: {
      type: [String, Number],
      default: "",
      required: true,
    },
  },
};
</script>

and here is the parent Component:

<template>
  <div>
    <form>
      <h3>Name & describe your event</h3>
      <BaseInput
        label="Title"
        type="text"
        placeholder="Enter title..."
        v-model="title"
      />
      <BaseInput
        label="Description"
        type="text"
        placeholder="Enter Description..."
        v-model="description"
      />
      <h1>{{ title }}</h1>

      <h3>Where is your event?</h3>

      <BaseInput
        label="Location"
        type="text"
        placeholder="Enter Location..."
        v-model="location"
      />
      <button type="submit">Submit</button>
    </form>

    {{ description }}
    {{ location }}
  </div>
</template>

<script>
import { reactive, toRefs } from "vue";

import BaseInput from "../components/BaseInput.vue";

export default {
  name: "MainForm",
  components: {
    BaseInput,
  },
  setup() {
    const event = reactive({
      category: "",
      title: "2pacShakur",
      description: "",
      location: "",
      pets: 1,
      extras: {
        catering: false,
        music: false,
      },
    });
    
    return {
      ...toRefs(event),
    };
  },
};
</script>

CodePudding user response:

Try to emit update:modelValue :

const { reactive, toRefs } = Vue
const app = Vue.createApp({
  setup() {
    const event = reactive({
      category: "",
      title: "2pacShakur",
      description: "",
      location: "",
      pets: 1,
      extras: {
        catering: false,
        music: false,
      },
    });
    
    return {
      ...toRefs(event),
    };
  },
})
app.component('BaseInput', {
  template: `
    <div >
      <label for="base-input">{{ label }}</label>
      <input
        
        :placeholder="placeholder"
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
        v-bind="$attrs"
        id="base-input"
      />
    </div>
  `,
  props: {
    label: {
      type: String,
    },
    placeholder: {
      type: String,
    },
    modelValue: {
      type: [String, Number],
      default: "",
      required: true,
    },
  },
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
  <div>
    <form>
      <h3>Name & describe your event</h3>
      <base-input
        label="Title"
        type="text"
        placeholder="Enter title..."
        v-model="title"
      ></base-input>
      <base-input
        label="Description"
        type="text"
        placeholder="Enter Description..."
        v-model="description"
      ></base-input>
      <h1>{{ title }}</h1>

      <h3>Where is your event?</h3>

      <base-input
        label="Location"
        type="text"
        placeholder="Enter Location..."
        v-model="location"
      ></base-input>
      <button type="submit">Submit</button>
    </form>

    {{ description }}
    {{ location }}
  </div>
</div>

  • Related