What is the best way to retrieve v-model data from a child component in Vue 2?

I created a unique input component and now I need to retrieve data from it in the parent component. Initially, I followed the guide and used the component as suggested:

Input.vue

<input
      :value="value"
      @input="$emit('input', $event.target.value)"
      class="w-full border-[1px] bg-transparent p-4 lg:text-sm placeholder:text-[#97999B]"
      :placeholder="placeholder"
      :class="statusStyles"
    />

MyComponent.vue

    <Input
          placeholder="Phone number"
          type="text"
          v-model="phone"
        />

Initially everything worked fine, but then I divided this code into components and introduced another wrapper, resulting in the following structure:

Form.vue

<OrderFormInfo
      v-if="step === 'info'"
      :name="name"
      :apart="apart"
      :city="city"
      :phone="phone"
      :postal="postal"
      :region="region"
      :address="address"
      @next-step="handleNext"
    />

OrderInfo.vue

        <Input
          placeholder="phone number"
          type="text"
          v-model="phone"
        />
        <Input
          placeholder="recipient name"
          type="text"  
          v-model="name"
        />

Input.vue

<template>
  <div class="w-full space-y-[10px]">
    <input
      :value="value"
      @input="$emit('input', $event.target.value)"
      class="w-full border-[1px] bg-transparent p-4 lg:text-sm placeholder:text-[#97999B]"
      :placeholder="placeholder"
      :class="statusStyles"
    />
    <p v-if="errorStatus" class="text-red-500">{{ errors[0] }}</p>
  </div>
</template>

<script>
export default {
  props: {
    errors: Array,
    sucess: Boolean,
    value: String,
    errorStatus: Boolean,
    placeholder: String,
  },
  computed: {
    statusStyles() {
      if (this.errorStatus) {
        return "border-red-500 text-red-500";
      }
      if (!this.errorStatus && this.value.length > 3) {
        return "bg-white border-black text-black";
      }
      return "text-black  border-[#97999B]";
    },
  },
};
</script>

Now the challenge is how to fetch the data from OrderInfo.vue in Form.vue? I attempted passing data through props but encountered an error stating that it's not allowed in Vue. Can someone please guide me on using v-model with nested components?

Answer №1

To monitor the props, simply create a watcher function in the parent component (Form.vue) within the mounted hook.

All you need to do is add a ref to your highest-level child component. For example:

<order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>

Check out the Live Demo below:

Vue.component('orderFormInfo', {
  props: ['name', 'phone'],
  template: `<div>
    <input-field
      placeholder="phone number"
      type="text"
      v-model="phone"/>
    <input-field
      placeholder="recipient name"
      type="text"
      v-model="name"/>
  </div>`
});

Vue.component('inputField', {
  props: ['value', 'placeholder'],
  template: `<input
:value="value"
@input="$emit('input', $event.target.value)"
:placeholder="placeholder"
/>`
});

var app = new Vue({
  el: '#form',
  data: {
    name: 'Alpha',
    phone: '1111111111'
  },
  mounted() {
    this.$watch(
      "$refs.orderFormComponent.phone", (newVal, oldVal) => {
         console.log(newVal, oldVal)
      }
    );
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="form">
  <order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>
</div>

Answer №2

I managed to figure it out by doing some research online and came across an article that helped me make the necessary changes:

Updated code in OrderFormInfo.vue:

     <Input
          placeholder="Phone number"
          type="text"
          :error-status="false"
          :errors="[]"
          :value="phone"
          @input="$emit('input-phone', $event)"
     />

Updated code in OrderForm.vue:

  <OrderFormInfo.
      v-if="step === 'info'"
      :name="name"
      @input-name="name = $event"
      :phone="phone"
      @input-phone="phone = $event"
      @next-step="handleNext"
  />

Answer №3

If you're looking to update data between components in Vue.js, there are a variety of methods you can use:

  1. Utilizing an Event Bus to emit events when data changes.
  2. Implementing Vuex for state management and universal access.

While the above solutions require some setup, a simpler approach would be using this.$root.$emit to trigger events across components without relying on global variables or props.

Feel free to test out this functionality by altering the phone and name values within the input field (OrderFormInfo.vue). You should observe these changes reflected in the parent component, Form.vue.

To ensure smooth operation:
When passing props from Form.vue to OrderFormInfo.vue, refrain from directly modifying those props. Instead, duplicate the props into data variables and make modifications there. For further details on why this approach is recommended, refer to this resource.

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 initiate an onload event from a script embedded within a jquery plugin?

Currently, I am in the process of developing a jQuery plugin. One issue that I have encountered involves a script tag being dynamically added for LivePerson.com. The script is supposed to trigger an onLoad function specified in the configuration. However, ...

Issue with the functionality of socket.io callback functions

Previously, I used to utilize the socket.io emit callback in the following manner: On the client side: mysocket.emit('helloworld', 'helloworld', function(param){ console.log(param); }); On the server side: var server = r ...

Retrieve only the initial tag content using jquery

My goal is to extract the "22" from the following code... <div class="left"> <a class="count-link" href="http://url1.com"> <span>22</span> users </a> <a class="count-link" href="http://url2.com"> <span>10</span ...

Only one active class is allowed in the Bootstrap Accordion at any given time

I have implemented Bootstrap's accordion on my webpage, consisting of two different sections with unique content. Upon loading the page, the active class defaults to the first element of the first section. However, if I navigate to the "Second" sectio ...

Having trouble resolving an error while attempting to incorporate an npm module into a vanilla JavaScript application

I admit my lack of expertise in building modern JavaScript apps is becoming evident. Currently, we have a Capacitor app that uses plain JavaScript without any build tools, and it functions well. Our goal is to incorporate Microsoft Code Push support throu ...

Inquiry regarding delays in updating and retrieving data with Mongoose in Node.js

I recently faced an issue related to the CRUD development process. Whenever I update a property and check the response in Postman, it always shows the previous data. For instance, after clicking send on Postman, it shows "weeks" : "11" instead of "10". Che ...

The Vue router-view is mistakenly loading the parent component instead of displaying its own content

Here is a simple route configuration: { path: '/', component: Home, }, This route configuration sets the path to the home page and loads the Home component when the path is '/'. However, I am encountering an issue where the Po ...

Fill input text fields with values based on dropdown selection and start with 2 input fields pre-filled

Initially, the issue is that there are 2 input text fields displayed. Depending on the selection from a drop-down menu ranging from 2 to 6, additional input fields should be added or removed. Here's my code: function addElements(selectElement) { va ...

A directive containing a template

I'm facing a unique challenge where I have to nest a template inside another template within my directive. The issue arises because AngularJS doesn't recognize ng-repeat code inside attributes. In an ideal scenario, here is how I envision my cod ...

What could be causing my Javascript element to continue moving past 200px?

My code has a "voila" element that is not stopping after reaching 200px. What could be the issue in the logic of the code and how can I fix it? var voila = document.querySelector(".voila"); voila.textContent = "hahahaha"; voila.style.position = "absolute" ...

Updating the rotation of a grandchild in Three.js Object3D

In my current project, I am attempting to make the grandchild of a rotated Object3D element face towards the camera using the lookAt() method. I have experimented with various approaches to achieve this. However, the source code for the Object3D.lookAt() ...

Tips for removing a row without impacting the rest of the rows

I'm currently developing a VueJs parent component with the ability to generate rows dynamically. This component invokes another component responsible for populating two dropdowns using axios - one for categories and the other for subcategories (with t ...

Guide on How to Navigate JSONP Responses in Goodreads

I've been working on a project that involves pulling data from Goodreads' API in order to display the rating for a specific book. However, I've hit a bit of a snag. Upon requesting data from this URL (https://www.goodreads.com/book/review_c ...

Leverage the power of regular expressions in JavaScript for organizing and handling source files

Embarking on my coding journey with JavaScript, I have also been exploring the world of Three.js, a webgl library. After watching tutorials and conducting experiments, I am proud to share my latest creation: . In my code, you'll notice that the obje ...

Navigate to the recently added entry using Router.push in your NextJS/Supabase project, leading to no return value

In the process of developing an application that allows users to register shipments between different locations, I encountered a roadblock. Once a user creates a new shipment and saves it, they should be able to add goods to it. However, despite my efforts ...

What steps can be taken to resolve the error message: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data?

I'm facing an issue while trying to retrieve data for my map using an AJAX call. The error message I receive is: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data. Interestingly, two previous datasets in my applicatio ...

Turn on and off scrolling of DIV content when hovering over it

How can I create a div that automatically scrolls to the bottom on hover? I tried implementing the code below, but it doesn't work as expected. It jumps to the bottom of the div's height on first hover and transitions smoothly on second hover. . ...

Oops! Looks like there was a mistake. The parameter `uri` in the function `openUri()` needs to be a string, but it seems to

While working on my seeder file to populate data into the MongoDB database, I encountered an error message that reads: Error : The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `m ...

Exploring the vertices with the updated PlaneBufferGeometry feature in ThreeJS

I've recently learned that PlaneGeometry is no longer supported and suggest using PlaneBufferGeometry in the latest updates. While my code used to function properly in versions prior to R125, I am unsure how to modify it to work with PlaneBufferGeomet ...

Vue component with a variable number of rows, each containing a variable number of input fields

I am currently working on creating a form that can have a variable number of steps. Users should be able to add an additional step by clicking a button. Each step will contain some input fields and buttons to dynamically create more input fields. For inst ...