14. Two-way data binding with v-model

Finally, the day has come, to understand the missing piece of the puzzle, data binding. So far, we have seen how to use interpolations, v-bind for attribute binding and v-on to listen to events. The missing piece was v-model which is used for two-way data binding and this is exactly what we will be concentrating on today!

Big word alert!

Two-way data binding: This is just a relation between the model (data object in the Vue instance) and the view. Any change made in the view (say, by the user) will immediately be reflected in the underlying Vue model and will be updated at all places where this data is being rendered in the view. In other words,

  1. View is updated with the change made to the data property (model)
  2. And, the data property (model) is updated whenever a change is made in the view

Is your head spinning yet? No worries! We will understand this concept by walking through an example.

v-model directive

This two-way binding is usually created with form inputs and controls. And v-model is the directive used to achieve just that! To be more specific, below are the exact HTML elements with which v-model is used,

  • <input>
  • <textarea>
  • <select>
  • Components (we will be covering this topic in the “Advanced VueJS” section)

Example walkthrough

Let us take an example with <input> element to show a text field on the webpage. Let us also have a “message” property in the Vue instance’s data object which acts as our Vue model and a <p> tag to render the value using mustache syntax (text interpolation). Now, we want to,

  1. Populate the text field with the message property’s value, say, “hi” i.e., updating the view with the model.
  2. Whenever the value, “hi” is changed by the user in the text field, it has to be updated in the data property, message in our case i.e., updating the model with changes in view and
  3. Also rendering it in the <p> tag simultaneously

All these three steps can be done by adding the v-model directive to the <input> tag and binding the “message” property to it like so,

<input type="text" v-model="data_property_to_bind"></input>

Index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Hello Vue!</title>
    <!-- including Vue with development version CDN -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <h2>Welcome</h2>
      <div>
        <!-- two-way binding with v-model -->
        Greeting Message:
        <input type="text" v-model="message"></input> 
        <p>The message is: {{ message }}</p>
      </div>
    </div>
    <!-- including index.js file -->
    <script src="index.js"></script>
  </body>
</html>

Index.js

new Vue({
  el: "#app",
  data: {
    message: "hi"
  }
});

So, the v-model directive tells vue.js to set up a two-way binding for the input field and the message data property mentioned within the quotation marks. All this happens reactively of course!

The initial output is as below.

v-model initial output

The right half in the image shows Vue DevTools pane. The data object with the message property and its value can also be seen.

As we change the message in the text field from “hi” to “hello”, with every character that we type, it will reactively get updated in the underlying data model (shown in the Vue Devtools) and updated in the view where we output using mustache syntax in the <p> tag.

reactivity with v-model

I highly recommend you to open Vue Devtools as shown in the image and change the value in the text field to see this change happening reactively. It will be a feast to your eyes! I can assure that.

Modifiers

v-model comes with three modifiers. In case you missed the modifiers part, check this out.

Usage: Following the v-model directive, add a dot and specify the modifier.

  • .lazy– sync the input with the data after change events instead of input events
<input v-model.lazy="message">
  • .number– used to cast valid input string to numbers
<input v-model.number="age">
  • .trim– to trim the user input automatically
<input v-model.trim="message">

The code is available in the GitHub repo as always.

Play around with that and notice how Vue correctly updates the element based on whether the input type is a text field, checkbox, radio button, select, multi-select, text area element and so on… It looks and sounds magical because all the syntax sugar you need to achieve this elephant-sized task is a single directive, v-model. Feel free to give a shout out in the comments section in case you bump into any issues.

Have a great day ahead!

4 Comments

  1. I have a issue with using v-model on a input of type ‘text’. The binding only works one way, what is written on the input gets set on the parameter but if the parameter is changed the input value doesn’t.
    I’ve tried passing the value with ‘v-bind:value’ but that creates a conflict issue with v-model.

    • Hi Bruno,
      Please could you share the code that was tried? I will be able to answer your question and provide a solution.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.