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

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

filrakowski profile image Filip Rakowski Originally published at dev.to Updated on ・2 min read

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">

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"
>

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>

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" />

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'
}

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>

..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!

Discussion

pic
Editor guide
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
shahid_karimi profile image
SᕼᗩᕼIᗪ KᗩᖇIᗰI

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.