[Vuejs]-Why does Input not storing inputted data in modelValue Prop

3👍

There are few things to fix:

  1. PrimeVue component InputText has no prop value but modelValue (to support v-model) – InputText Docs + read Using v-model on Components to learn a difference between v-model on native inputs vs custom components

  2. InputText is not a native input element, so there is no point to listen for a input event. The component is emitting update:modelValue event. Also event payload is not native event so event.target.value makes no sense, just use valuesource

  3. There is no point in duplicating the p-filled as InputText does this already (see source above)

// FormInput.vue

<template>
  <span :class="wrapperClass">
    <i :class="iconLeft" v-if="iconLeft" />
    <InputText
      :type="type"
      :modelValue="modelValue"
      @update:model-value="onInput"
    />
    <label for="username">{{ label }}</label>
    <i :class="iconRight" v-if="iconRight" />
  </span>
</template>
<script lang="ts">
import InputText from "primevue/inputtext"
import { defineComponent } from "vue"

export default defineComponent({
  name: "FormInput",
  emits: ["update:modelValue"],
  components: { InputText },
  props: {
    iconLeft: {
      type: String,
      default: "",
    },
    iconRight: {
      type: String,
      default: "",
    },
    error: {
      type: String,
      default: "",
    },
    label: {
      type: String,
      default: "",
    },
    type: {
      type: String,
      default: "text"
    },
    modelValue: {
      type: String,
      required: true
    },
  },
  computed: {
    wrapperClass(): any {
      return {
        "p-float-label": true,
        "p-input-icon-left": this.iconLeft,
        "p-input-icon-right": this.iconRight,
      }
    },
  },
  methods: {
    onInput(value: any): any {
      this.$emit("update:modelValue", value)
    },
  },
})
</script>

Usage:

<FormInput v-model="data" />
<!-- OR -->
<FormInput :modelValue="data" @update:model-value="data = $event" />

Demo:

const app = Vue.createApp({
  data() {
    return {
      text: "default value",
    }
  },
});

app.component('FormInput', {
  emits: ["update:modelValue"],
  components: {
    'inputtext': primevue.inputtext
  },
  template: `
  <span :class="wrapperClass">
    <i :class="iconLeft" v-if="iconLeft" />
    <inputtext
      :type="type"
      :modelValue="modelValue"
      @update:model-value="onInput"
    ></inputtext>
    <label for="username">{{ label }}</label>
    <i :class="iconRight" v-if="iconRight" />
  </span>
  `,
  props: {
    iconLeft: {
      type: String,
      default: "",
    },
    iconRight: {
      type: String,
      default: "",
    },
    error: {
      type: String,
      default: "",
    },
    label: {
      type: String,
      default: "",
    },
    type: {
      type: String,
      default: "text"
    },
    modelValue: {
      type: String,
      required: true
    },
  },
  computed: {
    wrapperClass() {
      return {
        "p-float-label": true,
        "p-input-icon-left": this.iconLeft,
        "p-input-icon-right": this.iconRight,
      }
    },
  },
  methods: {
    onInput(value) {
      this.$emit("update:modelValue", value)
    },
  },
});

app.mount('#app');
<link href="https://unpkg.com/primevue/resources/themes/saga-blue/theme.css" rel="stylesheet">
<link href="https://unpkg.com/primevue/resources/primevue.min.css" rel="stylesheet">
<link href="https://unpkg.com/primeicons/primeicons.css" rel="stylesheet">

<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/primevue/inputtext/inputtext.min.js"></script>

<div id="app">
  <form-input v-model="text"></form-input>
  <pre>
    {{ text }}
  </pre>
</div>

Leave a comment