Vue Js v-model to the rescue…

ankita srivastava
7 min readJun 13, 2022

I come from a React Js background with around 3 years of experience. When I start learning Vue Js, a few concepts seems confusing to me. It took some time to get used to these concepts, v-model was one of them. v-model does a lot of things out of the box for us. Let's deep dive into v-model to understand how beautiful it is 😇

https://media.giphy.com/media/QUENDfi6DEMLzQ0CKt/giphy.gif

What is a v-model?

In general, when we write react component, let’s say which has some input element, we used to have a state for holding the input data and then we used to trigger a method on input event. Now, if I write something similar in Vue, it will look like this:

<input
:value="message"
@input="(event) => message = event.target.value">

That means, we are triggering input here manually and then setting the state (message) which again gets assigned to your input element using value attribute.

Now in vueJs, v-model says let me take this responsibility from you and help you with the manual update part. That means, we just need to have a state/data, and assigned it to the v-model, the event(input for input element) triggering part will be taken care of by the v-model and our code will look like this:

<input v-model="message">

V-model does two-way binding for us i.e., if input changes the data(message) will update or if data changes it updates the input. Pretty simple isn’t it!!

Note: v-model will take the control for triggering the event and which event will get triggered, this based on the element which is getting used. e.g.,

For <input> with text type, it triggers @input event and use value property, for <input type="checkbox"> or <input type="radio"> it triggers @change event and usechecked property, for <select> it triggers @change event and usevalue property.

Note: All these event listening works well for native tag like input, select etc. but for custom vue element, v-model works differently where you need to explicitly emit the event with the updated value and v-model does the job of listening the updated value and changing it.

Honestly, you will find all these things in the Vue documentation but there is one use case that I want to share that took sometime to understand initially being new to VueJs. Let’s discuss this and also explore v-model behaviour for vue custom element.

The use case for v-model

Scenario: We have 1 parent component, which has 3 child components let's say child1, child2, and child3. We will be selecting some data in each child component and finally, at child3, we will do a submission where all the data get submitted. You can consider it like, we are building a form where you have 3 pages and finally we submit all the selected data on the third page.

Parent.vue
Child1.vue
Child2.vue
Child3.vue

We thought of 2 approaches to solve this use case:

Approach 1: Coming from React background, Initially, our team thought that we will create a Parent component that will hold all the data, methods and submission logic in the parent component itself, as parents should be aware of all the child data. We will pass all the data as prop and function as a reference to the child component and trigger the function from the child whenever required.

Problem with Approach 1: In this approach, there is one problem. In the child1 component, we have two dropdowns that are interrelated i.e., when you select the first dropdown value, the second dropdown options will get changed accordingly. We have created a method for doing the parsing which looked like this:

Now the problem was where to keep this method, in Child1 or in the parent. The data this.secondDropdownValue was data in Parent and prop in child1 component, so we cannot keep this method in child1 as we cannot update/change prop. Now, we are forced to keep this method in the parent component along with the dropdown options data in the parent.

When we decided to keep it in the parent component, we realised that this method's responsibility should be with the child and not with the parent because parent should not deal with parsing/clearing any child data and this way we landed on approach 2.

Approach2: Now, we were thinking that we should maintain data in each child component so that all such methods as parsing responsibility will be along with the correct owner which was child1 in the previous case.

Now when we want to do the final submission where we need all data, we again face challenges because in child3, as we need child1 and child2 data and siblings should not share data as per recommendations. This made us realise that no matter what, we need to maintain all the child data at the parent level so that during final submission you can reach out to the parent and get all your data i.e., data at both parent and child. Basically, we were maintaining data in child, and then on any event(e.g., input, change) trigger, we do emit a custom event from child component and then we will explicitly ask parent to listen that event and update the data manually.

Problem with Approach 2: In approach 2, though we have solved the problem of moving the parsing method to the child1 component and everything else is working fine, we might end up in a situation of data inconsistency. As we are maintaining data at 2 places, child as well as parent, If we forget to update data at one place then we end up seeing inconsistent data in our UI, because parent and child will be having different data now.

Now, both approaches have some or the other problems. we were looking for some other solution as this was the very likely occurring scenario, and then the v-model comes to rescue. Let's discuss how we solved this issue:

We kept all our data at the parent component and passed it as a prop to the child component. Parent data will always be single source of truth to avoid inconsistency. Now the parent and child component will get updated like below:

Parent.vue

https://gist.github.com/sankita15/c34a4690ea415b854731960cf6752f4d

Child1.vue

https://gist.github.com/sankita15/720d5077690e382ea101b62783fea432

Now here in the updated child1 component, you can see updateFirstDropdownValueAndLoadSecondDropdownOptions method which does the job of updating firstDropdownValue, which is prop in updated child1 component. If you check updateModelValue(event, type) method, we explicitly triggered event update:firstDropdownValue or update:secondDropdownValue based on the type we are triggering for, so that v-model in Parent component will listen to it automatically.

Note: update:firstDropdownValue trigger will update firstDropdownValue data in the parent component as v-model will listen it automatically for firstDropdownValue, and same goes for the update:secondDropdownValue.

This method updateModelValue(event, type) gets executed using a listener @update: model-value in the dropdown component. Now, you can assume dropdownContainer as a custom component which has a title and a dropdown.

Note: We did explicit event listening using @update: model-value in the Child1 component for dropdown, because here we introduced two level of nesting which is Parent -> Child1 -> DropdownContainer. As Child1 cannot use v-model on the prop(firstDropdownValue, secondDropdownValue), it cannot listen the event updates automatically like v-model and hence explicit event listening was required. This explicit event listening is not required if it was one level of nesting i.e., Parent -> Child1 where child1 update will be automatically listened by parent v-model.

if you see loadSecondDropdownOptions method, you will see the first line which is emitting an event with an empty value. This is possible because the v-model at parent will listen, and the update event for secondDropdownValue data (present at the parent component) will update the data at the parent level. This way we update the parent without the need of duplicate data at the child and without creating a custom event and explicitly listening it at parent to update it. We do emitted multiple @update event but there is no custom event present anymore and v-model also listen the update event automatically without any explicit listening of event at parent level.

Everything is in sync now without the need for maintaining data in 2 places. This way v-model solves the problem that we faced in both approaches.

Note: v-model can be very useful in such cases when you don’t want to manage the update manually for 1 or 2 level of nesting. Incase, you have multiple level of nesting then we end up emitting multiple update event and it will become difficult to track the event.

Things you can do with v-model!

  • When you are using v-model in a custom component without explicit name, then in the child component, by default v-model gives a prop called modelValue, which can be used for reading the value of the passed prop. Let's see here, how it looks:

Parent component

In the above code, we are passing fruits data as a prop to the Child custom component.

Child component

In the child component, you get modelValue as a prop which can be used for various purposes.

Note: Let’s say we end up in the same scenario which we discussed earlier and because of this modelValue prop, now we will be updating the parent data by emitting events like this.$emit('update:modelValue', value) . As we did not provide specific names to v-model, it will pick up the default one which is modelValue.

  • v-model provides different modifiers which can be used as per the use case. For example :
    v-model.lazy: This modifier will sync your input with the data after the change event instead of on every input event.
    v-model.number: This modifier will typecast the user input to a number, works very similar to type=number.
    v-model.trim: This modifier will trim the extra whitespaces from the user input.
  • You can also create custom modifiers, which you can access from props via this.modelModifiers.modifierName but in case you have given a name to v-model like v-model: first, then you need to access this.firstModifiers.modifierName.

This is all I want to share as my learning for v-model with the forum. Hope it will help you in some way. Please provide your valuable feedback 🙂.

--

--