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

What is the best way to integrate JavaScript libraries into my NPM build process?

My current website is built using HTML and CSS (with SCSS) and I have been using an NPM build script. Now, I am looking to incorporate some JavaScript libraries into my site, such as lozad. I have already downloaded the necessary dependencies for the libr ...

$q.all - successfully resolving some HTTP requests while encountering errors on others

I encountered a coding scenario like this angular.forEach(config.tvshows.shows, function(show) { promises.push($http.get('http://epguides.frecar.no/show/' + show.replace(/\s|\./g, '') + '/next/')); }); re ...

Vue JS: Toggling Checkbox Selections

I'm attempting to create a functionality where checking one checkbox will uncheck another, similar to how radio buttons work. I'm relatively new to Vue.js, so I may be missing something in my code. Here are the two input elements: <label for=& ...

Whenever I try to utilize the "ng-list" in JavaScript, I encounter issues accessing the variable model

HTML <input type="text" ng-list ng-model="OtherHobby" />{{OtherHobby}} <br /> {{AllHobbys}} Javascript $scope.OtherHobby = []; $scope.AllHobbys = $scope.OtherHobby; I ran a test on this piece of code. The variable "OtherHobby" w ...

Automatically populate select boxes with values from a different source using PHP

I'm in the process of setting up automatic population for 2 select boxes on a website. When a user chooses a class, the second select box automatically displays the main specialization of that class. If the user selects Tank (for example), the third ...

Using Jquery's getJson method, we can easily fetch and retrieve the appropriate JSON string by

I have the following code snippet at the beginning of the JSON url: if(isset($_GET['template']) && $_GET['template']=="blue") { $inifile_path="ctr/subthemes/blue/"; } else { $inifile_path="ctr/subthemes/fresh-n-clean/"; } Addi ...

Is Turbopack compatible with frameworks other than NextJs?

With its impressive speed, it would be great to utilize it in various outdoor projects like Vite. Unfortunately, there does not seem to be much information about it on their website I also checked out https://github.com/vercel/turbo but the details were s ...

Reducing Time Series Data: Comparing Average vs Largest-Triangle-Three-Buckets Technique

Currently, I am utilizing Flot Charts to create line charts that display timeseries data. To streamline the visualization process and reduce the number of data points shown, I have implemented a downsampling technique by averaging data points within the s ...

Steps to Verify if Cookie is Turned Off in a Next.js Application

I have encountered an issue with my Next.js App. It seems to be functioning properly until I disable cookies in the browser. Is there a way for me to determine if cookies are disabled in the browser and display a corresponding message? I attempted to check ...

A simple guide on how to display a child object in a materialUI select dropdown from a parent object

I am developing a ReactJS application where I aim to showcase child objects from the parent object in a dropdown using materialUI select. Despite attempting to iterate over the object using the map() function, I haven't been able to retrieve values up ...

Decrease the length of a pre-authorized link

Looking for solutions to speed up the loading of a list containing pre-signed image urls. Is there a method to reduce the size of the images or accelerate their loading time? Experimented with converting images to canvases in an attempt to decrease file s ...

Is there a way to ensure that GIFs in jQuery Mobile always start from the beginning?

My cross-platform mobile app built with jQuery Mobile is a small quiz application. After each correct or wrong answer, I display a 3-second GIF. Currently, I have set up the code to show the GIF for 3 seconds before moving on to the next page: else if ($. ...

Issue with Node's jsonwebtoken library: jwt.sign() method fails to include payload in generated token

I am currently working on developing an API with Node.js and have configured const jwt = require('jsonwebtoken') to handle JWTs. However, I am facing an issue where the generated token does not contain the payload information. To troubleshoot thi ...

Obtain the coordinates of the pixel in an image on the canvas when a mouse

I am currently working on a project that involves using canvas. I have set a picture as the background of the canvas and would like to be able to get the original pixel point when clicking in the image area. In order to achieve this, I need to convert canv ...

Response from the controller upon choosing a value from the selection dropdown

Scenario: In this scenario, there are two tables in consideration: Firm table : ID (string), Firm(string) Firms table: FirmID(string FK), Name(string) The goal is to select a value from the Firm table, pass it to the controller as Firm, and then execut ...

When using sequential jQuery 'pages', an error referencing the third frame occurs

I am new to using javascript/jquery and have been experimenting with the w3schools tutorials and jquery documentation. I created a page where user input is accepted and javascript prints output based on that input. I tried modifying it to work sequentially ...

Can you provide guidance on how to use Javascript to submit a form specifically when the input name is labeled as "submit"?

Query: How can I use Javascript to submit a form when one of the form inputs is named submit? Scenario: I need to send users to another page using a hidden HTML form. Unfortunately, I cannot modify the names of the inputs in this form because it needs to ...

angular data binding returning the identifier instead of the content

I have been dealing with managed fields retrieved from a web server in the following format: { "fields":{ "relationshipStatus":[ { "fieldId":4, "name":"Committed" }, { "fieldId":2, ...

Saving the AJAX response object in a global variable - Important fields are not being retrieved

Currently, I am developing an asynchronous webpage in Grails wherein I invoke a controller and display the response as a D3.js network. To ensure further usability, I saved the object as a global variable. Despite the successful execution of the function u ...

Tips for refreshing the page using NavLink from React-Router?

Is there a way to use NavLink to highlight buttons with an active link and still load the page like an anchor tag? ...