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

Filip Rakowski - Apr 8 '19 - - Dev Community

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!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player