Create a Vue.js wrapper component that can bind multiple values together

One of the components in my project is an input wrapper that includes a Select and a Freeform text box for entering an exact amount. I'm struggling to bind the Freeform text box to both the parent field and the selected option. I'm unsure of how to emit the change/input events.

I am attempting to follow the guidelines outlined in the Custom Events documentation.

A simple example can be found here.

The InputWrapper component structure looks like this:

<template v-if="inputType === 'text'">
  <input type="text" v-bind:value="value" v-bind="$attrs" v-on="inputListeners">
</template>
<template v-else-if="inputType === 'select'">
  <select v-bind="$attrs" v-bind:value="value" v-on="inputListeners">
    <option value>Select</option>
    <option
      v-for="option in options"
      v-bind:value="option.Id"
      v-bind:key="option.Id"
    >{{option.Description}}</option>
  </select>
  <!--Only show the input if it's a "FreeformOption"-->
  <!--How do I make this update the parent??-->
  <input
    type="text"
    v-if="selectedOption.IsFreeformOption"
    v-bind:value.sync="freeformValue"
    v-bind="$attrs"
    v-on:update="$emit('update:person.ExactIncome', '111')"
    v-on:input="$emit('input:person.ExactIncome', '222')"
  >

  <!--Would ideally recursively call the InputWrapper component
   <InputWrapper
    inputType="text"
    v-if="selectedOption.IsFreeformOption"
    v-bind:value= "freeformValue"
    v-on:input="$emit('input', $event)"
    ></InputWrapper>
  -->
</template>

A live demo can be accessed by clicking here.

Integration with the model:

<InputWrapper
  id="incomeLevels"
  inputType="select"
  :options="incomeLevels"
  :freeformValue.sync="person.ExactIncome"
  v-model="person.IncomeLevelID"
></InputWrapper>

For proper functionality, wrap the freeformValue in a computed property and emit the change event there.

wrappedFreeform: {
      get() {
        return this.freeformValue;
      },
      set(v) {
        this.$emit("update:freeformValue", v);
      }
    }

Check out the fully functional demo HERE.

Answer №1

If you are currently using .sync in your code, it may lead to Vue warnings as shown below:

// InputWrapper
<input
  v-model="freeformValue" 
  >
// Demo
<InputWrapper
  :freeformValue.sync="person.ExactIncome"
></InputWrapper>

Another approach is passing an entire object as a prop, which avoids the warning messages, but this method may not always be the most optimal solution:

// InputWrapper
<input
  v-model="freeformValue.ExactIncome" 
  >
// Demo
<InputWrapper
  :freeformValue.sync="person" //pass an object here
></InputWrapper>

A more efficient solution recommended by @MisterIsaak involves setting up a computed property to handle the updating process without directly mutating the prop:

// InputWrapper
<input
  v-model="wrappedFreeform" 
  >

computed: {
  wrappedFreeform: {
      get() {
        return this.freeformValue; // here we just get the value
      },
      set(v) {
        this.$emit("update:freeformValue", v); // emmit an event instead of mutating the prop directly
      }
    }
}


// Demo
<InputWrapper
  :freeformValue.sync="person.ExactIncome" //the value will be updated properly
></InputWrapper>

Answer №2

When we mention 'Emit' here, we are referring to a specific function within the parent component.

In this particular scenario, the input field will look like:

<input
        type="text"
        v-if="selectedOption.IsFreeformOption"
        :value="freeformValue"
        @input="$emit('updateFreeFormValue', $event.target.value)"
      >

Meanwhile, in the parent component, you can find the following code:

<InputWrapper
      id="incomeLevels"
      inputType="select"
      :options="incomeLevels"
      :freeformValue.sync="person.ExactIncome"
      v-model="person.IncomeLevelID"
      @updateFreeFormValue="updateFreeFormValue"
    ></InputWrapper>

Additionally, your methods should include the following block of code:

methods: {
    updateFreeFormValue(value){
      this.person.ExactIncome = value;
    }
  },

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

From Google Assistant to Python Results

Is there a way to control a Bitcraze Crazyflie drone using Google Home? I'm looking to give the command "Drone fly to x3 y4" which will be processed through Firebase and result in the Google Assistant Output: "Flying to x3 y4". Additionally, I need an ...

Interact with HTML Radio Buttons to Trigger Input Opening

I need to have a message saying "We're sorry..." and a "black box" displayed only when the radio button is set to YES, otherwise keep it hidden. Can I achieve this using JavaScript only, or is there a way to do it with HTML alone? <h3 >Did you ...

Issues with Angular 2 loading properly on Internet Explorer 11

We are currently running an Asp.net MVC 5 web application integrated with Angular 2. The application functions smoothly on Chrome, Firefox, and Edge browsers, but encounters loading issues on IE 11, displaying the error illustrated in the image below: ht ...

What could be causing my sticky positioning to not function properly when I scroll outside of the designated

My website is organized into sections, with each section corresponding to a hyperlink in the navigation menu. I've applied the CSS property position: sticky to my navbar, which works as expected within the section bounds. However, I want my red navbar ...

What is the process for adjusting the height of a scrollbar thumb?

Is it possible to set a fixed height for the scrollbar and adjust the amount of content scrolled accordingly with CSS? Here is my current CSS code: ::-webkit-scrollbar { width: 30px; } /* Track */ ::-webkit-scrollbar-track { box-shadow: inset ...

What is the best way to use CSS to ensure that dynamic, data-driven characters can be properly displayed within a div

I'm in the process of updating a data-centric website that relies on information from an automated database engine. In the HTML, there's a fixed-size button containing text pulled from the database. I'm looking to incorporate some CSS styles ...

Difficulty with rendering subcomponents of child components in Vue 3

For my web application, I utilized Vue 3.0.5 along with Webpack 5.21.2 and Webpack CLI 4.5.0. One of the key elements is a global component named my-component.js: import SecondComponent from './second-component.vue'; app.component('global-co ...

transfer data from local array to global variable

Need help with returning array values using console.log(array);, currently it's displaying empty value []. Any tips or suggestions would be greatly appreciated. var array = []; var maxLength = 3; var delay = 250; //Shortened the delay var ticker = {}; ...

What is the best way to include a date range together with other placeholder variables in a PostgreSQL and Express setup?

Forgive me for what may be a basic question, but as I dive headfirst into teaching myself SQL & PostgresSQL, I've stumbled upon an issue. I'm attempting to insert a large number of placeholders into an INSERT statement, but I'm struggling t ...

Is there a way to store a SAFEARRAY (an array of bytes) into an HTML hidden field?

Is there a way to extract an array of bytes from an active-x component, save it in an html-form input hidden field, and then send it to the server using form-submit? I'm not sure how to accomplish this. MIDL: HRESULT Data([out, retval] SAFEARRAY(VAR ...

The XML data seems to be missing from the HTML page

I've been working on a project where I need to display XML data on an HTML page. To accomplish this, I'm using Django to generate the content in the XML file and Javascript to periodically check for new posts and load them onto the page. Below i ...

Tips for setting up a cleanup function in useEffect when making API calls within a context provider

Looking to showcase a list of products categorized and fetched from an API? Check out the code snippet below: const API = "https://dummyjson.com/products"; const ProductsList = () => { const { cate } = useParams(); //retrieving category fro ...

Scroll to make the div slide in from the bottom

I'm trying to achieve a similar effect like the one shown in this website (you need to scroll down a bit to see the divs sliding in). Although I'm not very proficient in JS, I was able to create a code that makes the divs fade in from 0 opacity ...

Understanding how to access POST content in Meteor.js is an important aspect

In my Meteor app, I am trying to retrieve data using POST requests. Here is the code snippet I am using on the server side: __meteor_bootstrap__.app.stack.splice (0, 0, { route: '/input', handle: function(req, res, next) { req.on(' ...

Encountering a Next.js prerendering issue when using getStaticPaths

I am currently developing a Next.js application. Here is the structure of my files: cpanearme -components -listitem.js -pages -home -index.js -firm -[id].js Below is the code for a list item that redirects to the dynamic rout ...

Retrieve the ID from either a search query or an insertion operation in MongoDB

I find myself frequently using this particular pattern. It feels a bit cumbersome to make two MongoDB calls for the task, and I am curious if there is a more efficient way to achieve this. My goal is to obtain the ID of an existing document, or.. create ...

Converting a momentjs datetime stored in MySQL in UTC format to local DateTime format

I have a column in my table named "registerdate" with the data type "datetime" in MySQL. Let's assume the current time is "2015-10-10 06:00:00" in local time. In the database, I am storing UTC time, so it will be converted to "2015-10-10 00:30:00" a ...

Experience a unique issue with Google Maps API where the map appears greyed out upon loading for the first time, and the specific

I'm facing a strange issue with Google Maps. When the map loads, all I see is a grey box with tools displayed, but no icons appear on the bottom-right corner - only white boxes. If I move the map to the left, the left areas load properly; however, mo ...

Executing transitionend Using Jest for Unit Testing

I am currently utilizing angular 8 along with Jest for unit testing. My challenge lies in adding a listener for the 'transitionend' event on an element, and I'm struggling to find a way to simulate/mock this event using Jest. this.animatedEl ...

Refreshing a component in VueJs after updating it

In the parent component, there is a list component as a child. I am performing a delete operation in the child component. However, after deleting a record, the list is not automatically updated unless I refresh the page. Is there a way to update the list ...