Vue 3 Option api: Issue with v-model input not propagating from child component to parent element

I am currently working on a new project using Nuxt 3, and I have encountered an issue with a contact form where the input values from a child component are not being received by the parent element. Let's dive into the code breakdown:

Parent Component:

<script setup>
    import { ref } from 'vue';
    const formElement = ref(null);

    const errorMessage = ref(null);
    const form = ref({
        name: null,
        subject: null,
        email: null,
        message: null
    });

    const submitForm = () => {
        if (!form.value.name || !form.value.subject || !form.value.message) {
            console.log(form.value);
            errorMessage.value = "please make sure your 'fullname', 'subject', and 'message' fields are filled";
        } else if (!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(form.value.email)) {
            errorMessage.value = "please fill in a valid 'email'";
        } else if (form.value.message.length < 3) {
            errorMessage.value = "please add some more context to the 'message'";
        } else {
            console.log("button clicked");
            console.log(form.value);
            formSubmit();
        }
    };

    const formSubmit = () => {
        const formElement = document.querySelector('form');
        console.log(formElement);
        // formElement.submit();
    };
</script>

<template>
<form action="https://formsubmit.co/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e78e898188a7829f868a978b82c98488c9928c">[email protected]</a>" method="POST" ref="formm">
        <UtilityMainInput name="Name" placeholder="Full Name" inputType="text" controlType="input" v-model="form.name"/>
    <UtilityMainInput name="Subject" placeholder="Subject" inputType="text" controlType="input" v-model="form.subject"/>
    <UtilityMainInput name="Email" placeholder="Email Address" inputType="email" controlType="input" v-model="form.email"/>
    <UtilityMainInput name="Message" placeholder="Tell us anything" inputType="textarea" controlType="textarea" v-model="form.message"/>
    <div class="empty-height"></div>
    <UtilityButton type="btn" size="medium" :onClick="submitForm">Send Message</UtilityButton>
</form>
</template>

Child Component (UtilityMainInput):

<template>
    <div class="normal-form">
        <label :for="name" class="label">
            {{name}}
        </label>

        <!-- text input -->
        <input 
            v-if="controlType === 'input' && inputType ==='text'" 
            type="text" 
            maxlength="50"
            :name="name" 
            :value="value" 
            @input="$emit('input', $event.target.value) ">
        <!-- email input -->
        <input 
            v-if="controlType === 'input' && inputType ==='email'" 
            type="email" 
            :name="name" 
            :value="value" 
            @input="$emit('input', $event.target.value) ">
        <!-- textarea input -->
        <div class="textarea" v-if="controlType === 'textarea'">
            <textarea  
                :name="name" 
                :value="value"
                @input="$emit('input', $event.target.value) ">
            </textarea>
        </div>
    </div>
</template>


<script>
export default {
    props: {
        name: {
            type: String,
            required: true
        },
        placeholder: {
            type: String,
            required: false,
            default: "text goes here"
        },
        inputType: {
            type: String,
            required: false,
            default: "text"
        },
        controlType: {
            type: String,
            required: false,
            default: 'input'
        },
        value: {
            type: String,
            default: ''
        }
    },
}
</script>

Whenever I attempt to submit the form after filling it out, all the values in the parent component's data properties show up as null. Even though I have used v-model to bind them, the parent is not updating with the child's input values. Can anyone help me identify the reason behind this issue?

Answer №1

One notable change introduced in Vue 3 affects the Option API. For more details, refer to the official documentation.

Vue 2 version:

<input
  :value="name"
  @input="name= $event.target.value"
/>

Vue 3 version (Both Option api and Composition api):

  • value -> modelValue
  • @input -> @update:modelValue
<CustomInput
  :model-value="name"
  @update:model-value="newValue => name = newValue"
/>

The updated code snippet is available here: here on Vue playground

<script setup>
import { ref } from 'vue';
import UtilityMainInput from './UtilityMainInput.vue';
const formElement = ref(null);

const errorMessage = ref(null);
const form = ref({
  name: null,
  subject: null,
  email: null,
  message: null
});

const submitForm = () => {
  if (!form.value.name || !form.value.subject || !form.value.message) {
    console.log(form.value);
    errorMessage.value = "please make sure your 'fullname', 'subject', and 'message' fields are filled";
  } else if (!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(form.value.email)) {
    errorMessage.value = "please fill in a valid 'email'";
  } else if (form.value.message.length < 3) {
    errorMessage.value = "please add some more context to the 'message'";
  } else {
    console.log("button clicked");
    console.log(form.value);
    formSubmit();
  }
};

const formSubmit = () => {
  const formElement = document.querySelector('form');
  console.log(formElement);
  // formElement.submit();
};

function test(e) {
  console.log(e)
}
</script>

<template>
  <form action="https://formsubmit.co/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="61080f070e210419000c110d044f020e4f140a">[email protected]</a>" method="POST" ref="formm">
    <UtilityMainInput name="Name" placeholder="Full Name" inputType="text" controlType="input" v-model="form.name" />
    <UtilityMainInput name="Subject" placeholder="Subject" inputType="text" controlType="input" v-model="form.subject" />
    <UtilityMainInput name="Email" placeholder="Email Address" inputType="email" controlType="input"
      v-model="form.email" />
    <UtilityMainInput name="Message" placeholder="Tell us anything" inputType="textarea" controlType="textarea"
      v-model="form.message" />
    <div class="empty-height"></div>
    <button @click="submitForm">Send Message</button>
  </form>
</template>
<template>
    <div class="normal-form">
        <label :for="name" class="label">
            {{ name }}
        </label>
        <!-- text input -->
        <input v-if="controlType === 'input' && inputType === 'text'" type="text" maxlength="50" :name="name"
            :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
        <!-- email input -->
        <input v-if="controlType === 'input' && inputType === 'email'" type="email" :name="name" :value="modelValue"
            @input="$emit('update:modelValue', $event.target.value)">
        <!-- textarea input -->
        <div class="textarea" v-if="controlType === 'textarea'">
            <textarea :name="name" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
            </textarea>
        </div>
    </div>
</template>


<script>
export default {
    emits: ['update:modelValue'],
    props: {
        name: {
            type: String,
            required: true
        },
        placeholder: {
            type: String,
            required: false,
            default: "text goes here"
        },
        inputType: {
            type: String,
            required: false,
            default: "text"
        },
        controlType: {
            type: String,
            required: false,
            default: 'input'
        },
        modelValue: {
            type: String,
            default: ''
        }
    }
}
</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

Nuxt middleware's redirect function is causing the state to become null

My Nuxt app has a middleware issue where everything works fine except when the redirect function is used. When I comment out the line with redirect('/admin') it functions properly, even showing state data in the console log. But as soon as I unco ...

Unable to determine why node.js express path is not working

const express = require("express"); const app = express(); app.use(express.static("public")); var dirname = __dirname; app.get("/:lang/:app",function(req,res){ console.log(req.params.lang + " " + req.params.app); ...

Using Node.js and Express to retrieve data from a MySQL database and update a table

My .ejs file contains a form that sends data to a MySQL database and then displays two tables with the retrieved data on the same page. However, I am facing an issue where the tables do not refresh after submitting the form, requiring me to restart the ser ...

The property being set in Angular is undefined, causing an error

I am struggling to understand why the code below is not functioning as intended: Main.html <div class="MainCtrl"> <h1>{{message.test}}</h1> </div> Main.js angular.module('myApp') .controller('MainCtrl', f ...

Deleting the v-stepper-header number with Vuetify

I have been searching everywhere in an attempt to resolve this issue, but I have not been able to find a solution. Is there a way to remove the numbers from the v-stepper-header? - Using Vuetify version: 1.5.6 Current: https://i.stack.imgur.com/gLxFX.png ...

Error code 405 (METHOD NOT ALLOWED) is received when attempting to make a post request to an API

Struggling to develop a basic front end that can communicate with my API. The API functions properly as I am able to retrieve and send data using the POSTMAN client. Fetching data from the server and displaying it on the frontend works fine, but encounteri ...

Using references to pass variables in TypeScript [Angular 8]

I have several variables within the html of this component that are assigned their values by the typescript file. The declaration in the html is as follows: <h1>{{myproperty1}}<\h1> <h1>{{myproperty2}}<\h1> <h1>{{myp ...

Unable to render a rectangle with React's canvas context.fillRect

Could anyone help me with drawing a rectangle using React? I'm having trouble getting it to work. I'm confused as to why the code below isn't showing a rectangle on the screen. class DrawingView{ constructor(props) { this.canva ...

In the frontend, I seem to have trouble accessing elements of an array using bracket notation, yet strangely it works flawlessly in the backend

I am encountering a peculiar issue as a newcomer to coding. I have an array retrieved from the backend database, and my goal is to access individual elements of this array in the frontend using bracket notation. While I can successfully access the elements ...

Detect errors in the `valueChanges` subscription of Firestore and attempt a retry if an error occurs

My Angular app utilizes Firestore for storing data. I have a service set up to retrieve data in the following way: fetchCollectionColors(name) { this.db.collectionGroup('collection-colors', ref => ref.where('product', '==&ap ...

Where is the source of this ever-changing image?

Recently, I decided to dive into the world of jQuery and experiment with a plugin carousel. However, I must admit it is all a bit overwhelming for me at the moment. Currently, I have the plugin installed and I am struggling to get rid of the bottom scroll ...

Setting up flowplayer for multiple div elements: a tutorial

I have a collection of videos and I am trying to set up the player for each div that holds a video. When constructing the divs in my JavaScript code, it looks like this: <div id="player+{{$index}}"></div> // The "player" + index is generat ...

Vuex: updating the state, but the computed property remains unchanged

I am currently working on a component that retrieves data from the 'endpoints' property in the store, makes some adjustments to it... computed: { ...mapState(['endpoints']), adjustedEndpoints () { ...

A more detailed explanation of Angular's dot notation

I came across a solution for polling data using AngularJS here on stackoverflow. In this particular solution (shown below), a javascript object is used to return the response (data.response). I tried replacing the data object with a simple javascript arra ...

module 'next/router' cannot be located or its associated type declarations are missing

Running into some issues with my NextJS application. An unusual error message is appearing, even though my code is functioning smoothly without any errors. import { useRouter } from 'next/router'; // Cannot find module 'next/router' or ...

Eliminate redundant XML entries when using jQuery autocomplete

Does anyone know how to prevent duplicate records from appearing in a jQuery autocomplete dropdown? I am pulling data from an XML file and want to ensure that each record is unique and only displayed once. You can see the issue here ...

Steps for verifying that an object property contains the necessary properties

I have a component that receives an object as a prop: <foo :ob='object'></foo> Within the component, the prop is defined like this: props: { ob: { type: Object, required: false, default: {} } } Typically, the expe ...

Exploring the possibilities of combining Selenium Code and F# with Canopy

Currently, I am facing the challenge of incorporating Selenium code into my F# project while utilizing the canopy wrapper. Canopy relies on Selenium for certain functions. My main struggle lies in converting Selenium code from Java or C# to fit within an ...

Creating a foolproof image polling platform: A step-by-step guide

I'm in the process of creating a webpage on my site that allows users to view a collection of images. The goal is for each registered user to choose one picture as their favorite, increasing that picture's score by one. The image with the highest ...

``There seems to be an issue with the Express app when trying to access it

I have set up an express app that I want other devices on the same WIFI network to access without requiring internet connectivity. The main computer hosting the app is assigned with a fixed IP address: 192.168.1.60 In my server.js file, I have included t ...