Exploring the use of v-model in Vue3 child components

After some exploration, I recently discovered that in Vue3, the v-model functionality does not work responsively or reactively with child Component.

The following code snippet showcases how the username data gets updated:

<template>
  <div>
    <input type="text" v-model="username" placeholder="Insert your username" />
    <p>{{ username }}</p>
  </div>
</template>

<script>
// Home.vue
export default {
  name: 'Home',
  data() {
    return {
      username: 'admin'
    }
  }
}
</script>

When text is entered into the input, the username data will also change accordingly.

However, when utilizing a Component as shown below:

<template>
    <input type="text" :class="'input-text ' + additionalClass" :placeholder="placeholder" />
</template>

<script>
// InputText.vue
import { defineComponent } from "vue"

export default defineComponent({
    name: 'InputText',
    props: {
        placeholder: {
            type: String,
            default: ''
        },
        additionalClass: {
            type: String,
            default: ''
        }
    }
})
</script>

I decided to update my code and incorporate the Component.

Please note that the Component has been successfully registered.

<template>
  <div>
    <input-text v-model="username" :placeholder="`Insert your username`" />
    <p>{{ username }}</p>
  </div>
</template>

<script>
// Home.vue
export default {
  name: 'Home',
  data() {
    return {
      username: 'admin'
    }
  }
}
</script>

Upon entering text, I noticed that the username data did not get updated, unlike the previous scenario. This issue led me to ponder if there exists a solution or at least a reference to what I am aiming to achieve.

Answer №1

Utilizing Vue3's script setup feature for more concise syntax

<template>
  <input type="text" v-model="val" @input="handleInput">
</template>

<script setup>
import {ref, defineProps, defineEmits, watch} from 'vue'

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
})
const emit = defineEmits(['update:modelValue'])

const val = ref('')

watch(() => props.modelValue, newValue => val.value = newValue, {
  immediate: true
})

const handleInput = () => emit('update:modelValue', val.value)
</script>

Answer №2

It is important to note that simply using v-model will not automatically update the underlying element. You will still need to handle this functionality within the component itself by exposing modelValue as a prop for it to function correctly. Here is an example of how you can achieve this:

<template>
  <input
    type="text"
    @input="handleInputChange"
    :value="modelValue"
    :class="'input-text ' + customClass"
    :placeholder="placeholderText" />
</template>

<script>
  // CustomInput.vue
  import { defineComponent } from "vue"

  export default defineComponent({
    name: 'CustomInput',

    emits: ['update:modelValue'],

    props: {
      modelValue: String,
      placeholderText: {
        type: String,
        default: ''
      },
      customClass: {
        type: String,
        default: ''
      }
    },

    setup(props, { emit }) {
      function handleInputChange(e) {
        emit('update:modelValue', e.currentTarget.value);
      }

      return {
        handleInputChange
      }
    }
  })
</script>

Answer №3

If you're looking for an easier way to manage v-model in a sub-component, check out the VueUse helper called useVModel. You can find more information at this link.

<script lang="ts" setup>
import { useVModel } from '@vueuse/core'

const props = defineProps<{
  modelValue: string
}>()
const emit = defineEmits(['update:modelValue'])

const model = useVModel(props, 'modelValue', emit)
</script>

<template>
    <input type="text" v-model="model" />
</template>

Answer №4

utilizing the OPTIONS API format

<template>
    <input type="text" v-model="val" @input="updateText" :value="modelValue">
</template>

<script scoped>
    export default {
        props: {
            modelValue: String,
        },
        methods: {
            updateText(event){
                this.$emit('update:modelValue', event.currentTarget.value)
            }
        }
    }
</script>

Answer №5

Back in the day, this code used to work perfectly fine:

Your InputText element

<template>
    <input :value="value"
           @input="({target}) => $emit('input', target.value)"/>
</template>

<script>
    export default {
        props: {
            value: {}
        }
    }

Your main component

<template>
    <inputText v-model="inputValue"/>
</template>

<script>
    export default {
        components: {inputText},
        data: () => ({
            inputValue: null
        })
    }
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What sets apart .js and .ts files in the development of a Selenium Protractor framework?

As a newcomer to Selenium Protractor, I noticed that many tutorial videos on YouTube utilize .js files for test scripts. However, the framework in my current project utilizes .ts files instead. I am seeking assistance in comprehending the variances betwe ...

Hide jquery scroll bar

I am currently working on a WordPress plugin with the Twenty Thirteen theme. My goal is to display a modal when a div is clicked, and at that time I want to hide the scrollbar on the body of the page. Despite trying the following code snippet, it doesn&ap ...

React Router consistently displaying IndexRoute

This is the main file for my app: import React from 'react'; import { render } from 'react-dom'; import { browserHistory, Router, Route, IndexRoute } from 'react-router'; // Components import Main from './components/cor ...

Encountering a 'unknown column' error while using MySQL on a Windows operating system

A query is being executed on Node.Js with MySQL, resulting in the following: SELECT COUNT(DISTINCT t.uid) AS usersCount, COUNT(*) AS workingDaysCount FROM ( SELECT d.date, u.id AS uid, CASE TIMESTAMPDIFF(day, SUBDATE(d.date, WEEKDAY(d.date) ...

Warning: ComponentMounts has been renamed. Proceed with caution

I'm encountering a persistent warning in my application and I'm struggling to resolve it. Despite running npx react-codemod rename-unsafe-lifecycles as suggested, the error persists and troubleshooting is proving to be challenging. The specific w ...

Having difficulty breaking down values from an object

Attempting to destructure the data object using Next.js on the client side Upon logging the data object, I receive the following: requestId: '1660672989767.IZxP9g', confidence: {…}, meta: {…}, visitorFound: true, visitorId: 'X9uY7PQTANO ...

unable to perform a specific binary operation

Is there an efficient method to achieve the following using binary operations? First byte : 1001 1110 Second byte : 0001 0011 Desired outcome : 1000 1100 I am looking to reset all bits in the first byte that correspond to bit values of 1 in the secon ...

Unable to interpret AJAX request using PHP

I am trying to implement a feature where file contents can be deleted upon the click of a button. I have set up an ajax request that sends two variables - the filename and the name of the person who initiated the deletion process. The PHP function is runni ...

The way in which notifications for updates are displayed on the Stack Overflow website

Could someone shed some light on how the real-time update messages on this platform are created? For instance, when I am composing a response to a question and a new answer is added, I receive a notification message at the top of the page. How is this fun ...

What is the best way to verify the existence of an email address?

I'm currently using the jQuery validation plugin and everything is working fine, but I've hit a snag when it comes to checking email addresses. The issue is that the plugin returns either true or false based on whether the email exists or not. Ho ...

Utilize MaxMind GeoIP2 to identify the city accurately

I have been using this simple code to retrieve the city name through the maxmind service (geoip2). It has been working flawlessly and I am grateful to a fellow member of this site who shared this code with me. However, there is an issue when the user&apos ...

Stopping autoplay in React Swiper when hovering over it

I'm currently struggling to find a way to pause the autoplay function on swiper when hovering over it. Despite my efforts, I have not been able to locate a solution. <Swiper spaceBetween={0} navigation={{ ...

How can you style a two-item list in Material-UI React to display the items side by side?

I have a list that contains two items: 'label' and 'value'. This is the current layout: https://i.stack.imgur.com/HufX7.png How can I rearrange the items on the right to be positioned next to the label on the left? https://i.stack.im ...

Is it necessary for me to manually delete the node in JavaScript, or does the garbage collector handle that task automatically?

In order to remove the final node from a circular linked list using JavaScript, I plan on iterating to the second-to-last node and then connecting it back to the first node. This process effectively detaches the last node from the chain. My question is, ...

Uncovering the source of glitchy Angular Animations - could it be caused by CSS, code, or ng-directives? Plus, a bonus XKCD comic for some light-hearted humor

Just finished creating an XKCD app for a MEAN stack class I'm enrolled in, and I'm almost done with it. However, there's this annoying visual bug that's bothering me, especially with the angular animations. Here is the link to my deploy ...

The Image component in a test within Next.js was not wrapped in an act(...) during an update

After setting up a basic NextJS app with create-next-app and integrating Jest for testing, I encountered an error message stating "An update to Image inside a test was not wrapped in act(...)". The issue seems to be related to the Image component in NextJS ...

"Failure to manipulate the style of an HTML element using Vue's

<vs-tr :key="i" v-for="(daydatasT, i) in daydatas"> <vs-td>{{ daydatasT.Machinecd }}</vs-td> <vs-td>{{ daydatasT.Checkdt }}</vs-td> <vs-td>{{ daydatasT.CheckItemnm }}< ...

The CSS property overflow-x:hidden; is not functioning properly on mobile devices despite trying multiple solutions recommended online

Seeking help on a persistent issue, but previous solutions haven't worked for me. Looking to implement a hamburger menu that transitions in from offscreen. The design appears correctly on desktop and simulating mobile, but actual mobile view require ...

Can these similar functions be combined into a single, unified function?

Currently, I have 3 functions - and more to come soon - that all perform the same task. However, they control different enumerated divs/variables based on which div triggers the mousewheel event. I am wondering if there is a way to condense these very si ...

Issue with undefined object in ExpressJS PUT method

Attempting to utilize the PUT method for updating a record in my database, I encountered an issue with the object not being defined. ReferenceError: blogpost is not defined Following this tutorial for routing steps, I noticed that while the variable is d ...