DEV Community

Cover image for Vue during coffee break - using v-model with custom components.
Filip Rakowski for Vue Storefront

Posted on • Edited on • Originally published at dev.to

Vue during coffee break - using v-model with custom components.

The purpose of this series is to post tips & tricks about advanced Vue concepts that can be quickly applied to every application and give you a new weapon to approach problems.

In this short article, I will explain how v-model works and how it can be applied to every Vue component.

Understanding v-model

v-model is a common directive used in almost every Vue application. It's typically used to enable two-way data binding on form elements and works perfectly with input, checkbox, select, textarea and radio.

In below example, v-model applied on the input element binds someVal variable with native value property of the input.

<input v-model="someVal">
Enter fullscreen mode Exit fullscreen mode

Then the directive listens for native input event and updates someVal every time it's emitted.

So it turns out that we can rewrite the above code to well-known events and props with the same effect:

<input
  v-bind:value="someVal"
  v-on:input="someVal = $event.target.value"
>
Enter fullscreen mode Exit fullscreen mode

This is how v-model applied to regular input works under the hood.

Knowing this we can use v-model on every component that will emit input event and accept a value prop.

Take a look at this MagicCounter :

<template>
  <div>
    <button @click="changeValue(value-1)">-</button>
    <span>{{ value }}</span>
    <button @click="changeValue(value+1)">+</button>
  </div>
</template>

<script>
export default {
  props: ["value"],
  methods: {
    changeValue(newVal) {
      this.$emit("input", newVal);
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

Since we are emitting input event with a new value each time it's changed and accepting the value prop we can safely use v-model directive on this component:

<MagicCounter v-model="count" />
Enter fullscreen mode Exit fullscreen mode

Using v-model with custom components

Event thought input and value pair is the default setup for v-model depending on the input type, those bindings can be different (I strongly suggest checking it's source code for details). For example in checkbox element checked property and change event are used instead of default ones.

It turns out that we customize the event/prop pair accepted by v-model directive through a model property. For example, this is how it could look like for checkbox element:

model: {
  prop: 'checked',
  event: 'change'
}
Enter fullscreen mode Exit fullscreen mode

You might want to change the name of the event emitted by our MagicCounter to be more descriptive (for example modified).

Let’s see how we can make this custom event work with v-model

<template>
  <div>
    <button @click="changeValue(value-1)">-</button>
    <span>{{ value }}</span>
    <button @click="changeValue(value+1)">+</button>
  </div>
</template>

<script>
export default {
  props: ["value"],
  model: {
    event: `modified`
  },
  methods: {
    changeValue(newVal) {
      this.$emit("modified", newVal);
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

..and voilà! Now you know how to use v-model with every Vue component. I hope you'll find a way to use this knowledge very soon .

Here you can find a working example with a code from the post to play with.

Stay tuned for the next parts of the series!

Top comments (6)

Collapse
 
anduser96 profile image
Andrei Gatej

I remember this topic was a hard one to grasp when I first started learning Vue.

The nice parts of v-model come in when you have to deal with custom radio / checkbox components because you have to put more effort in order to get the expected behavior. At least this is what I've encountered.

Thank you for sharing!

Collapse
 
adlaws profile image
Andrew Laws

You explanatory rewrite of the v-model directive using the v-bind and v-on directives was an absolute lightbulb moment. Understanding this was, for me, the key to moving forward and this explanation is fantastic.

I had never come across the model property before, so I definitely also learned something here.

Thanks for putting this together!

Collapse
 
botmaster profile image
botmaster

Thank you for sharing! Useful!
I try to create a radio / checkbox components with no success.
How to deal with v-model and custom radio / checkbox ? It seem to be not so easy.

Collapse
 
shahid_karimi profile image
SᕼᗩᕼIᗪ KᗩᖇIᗰI • Edited

Try to create some realistic component like an input for typing fraction value (denominator and numerator)
Everyone, in every tutorial is making a custom shit component of the element.
Huh

Collapse
 
bcwhisnant profile image
Brandon Whisnant

The codepen link solved an issue I had been trying to solve for at least an hour. Using model: is a lifesaver!

Collapse
 
coderhyde profile image
Rickardo Hyde

Thank you soooo much. You explained it the best.