1
votes

I have been trying to learn how Vue's v-model works with custom input and also regular input components.

I have seen examples where v-model is tied to a value in the component and also in the template and both of these values will be different. I find this very confusing and I think it may be a misunderstanding of "two way binding". How do you have an input tied to two values.

Example:

//v-model in template

const myCustomInput = ('my-custom-input', {
  data() {
    return {
      myObj: 'hello'
    }
  },
  template: `<input v-model="myObj" >`
});

//v-model in component

<my-custom-input v-model="someOtherObj.str">

I have seen examples of having two v-models like this with different values both defined at the template level and component.

However, when looking at this SO post, the answer by @asemahle seems a lot more logical. Furthermore the official Vue docs does not even have 2 separate v-models on the template and the component Vue JS component basics

In the latter examples, it seems a lot more logical as there is only one v-model defined and tied to the input component rather than two.

Is the first example incorrect? And if it's not can someone explain more clearly how that works. I can't seem to find any real good documents on having two separate v-models for one input.

4

4 Answers

0
votes

Two-way binding is referring to binding the template html to only one object. In your example you are trying to bind it to two separate values as you stated which is simply a misunderstanding of the term two-way binding.

In two-way binding you are still only going to bind one v-model to one data element. The 'Two-way" part refers to the fact that once the v-model is bound to a data property when you type into the text box, the data property also changes. ALSO if you change the data property, maybe through a method or API call, then the textbox will also reflect that data change, hence the two-way data binding.

0
votes

In the example code you give, you have a component whose template includes a v-model on a native input:

template: `<input v-model="myObj" >`

That means that the input is (two-way) bound to myObj: changes to myObj's values will reflect in the input, and changes to the input will update the data item.

You then have an instance of that component with a v-model on it. The component will receive a value prop, and is expected to emit input events to achieve two-way binding. v-model on components is described here.

You do not have "an input tied to two values", but you might have a pointless binding, since the two things you bound are (apparently) unrelated. What you might want is for your component to act as a pass-through for the value, so that you can treat it almost like a native input. This example does that.

The custom input in the docs puts a v-model on the component and uses explicit binding for value and emit input from the native input element. You can replace those with a v-model to a settable computed, as I did in the example I linked in the paragraph above. The get returns value and the set performs the emit.

0
votes

Try using watch in the child component
Parent:

<OptionCarouselCards                                                   
  :selected-values="bevarageSelected"
  @optionSelected="getBeverage"
/>

Child:

<v-slide-group
  v-model="selected"
  @change="onSelect"
>


export default {
  props: {
    selectedValues: {
      type: [Array, Number],
      required: false,
      default: -1
    } 
 },
 data () {
   return {
     selected: this.selectedValues
   }
 },
 watch: {
   selectedValues (selectedValues) {
     this.selected = selectedValues
 }
},
methods: {
  onSelect (event) {
    this.$emit('optionSelected', this.selected)
  }
 }
}
0
votes

For multiple two way binding component arguments you can try something like this (vue 3):

<ChildComponent v-model:arg2="parentVariable1"  v-model:arg1="parentVariable2" />

And in the child component after changing value you have to just call:

this.$emit("update:arg1","some_value") 
or 
this.$emit("update:arg2","some_value_2") 

More details can be found in the vue docs