Two-Way Binding Using v-model
Vue has simplified the way to achieve two-way data binding by creating a directive that specifically watches a data property inside of your Vue component. The Vue directive v-model
will reactively change when the bound data property that Vue is watching changes. This directive is usually useful for HTML form elements that need to both display the data and modify it reactively, for example, input, textarea, radio buttons, and so on.
Two-way binding is achieved by adding the v-model
directive to the element you want bound and referring to a data prop:
<template> Â Â Â Â <input v-model="name" /> </template> <script> Â Â Â Â Â Â export default { Â Â Â Â Â Â Â Â data() { Â Â Â Â Â Â Â Â Â Â return { Â Â Â Â Â Â Â Â Â Â Â Â name: '' Â Â Â Â Â Â Â Â Â Â } Â Â Â Â Â Â Â Â } Â Â Â Â Â Â } </script>
Figure 1.23 represents the output generated by running the preceding code:
Be careful using this directive as binding a huge amount of data in this way can affect the performance of your application. Consider your UI and split these into different Vue components or views. Vue data in the local state is not immutable and can be redefined anywhere in the template.
Exercise 1.07: Two-Way Binding Using v-model
We are going to build a component using Vue's two-way data binding attribute v-model. Consider what it means to bind a piece of data in two ways. The context for this form of data model is usually forms, or where you expect both input and output data. By the end of the exercise, we should be able to utilize the v-model attribute in a form context.
To access the code files for this exercise, refer to https://packt.live/2IILld8.
- Open a command-line terminal, navigate into the
Exercise1.07
folder, and run the following commands in order:> cd Exercise1.07/ > code . > yarn > yarn serve
Go to
https://localhost:8080
. - Start by composing an HTML label and input element bound to the
name
data prop usingv-model
inside the template area:<div class="form">    <label>      Name      <input type="text" v-model="name" />    </label> </div>
- Finish binding the text input by returning a reactive data prop called
name
in the<script>
tag:<script> export default { Â Â data() { Â Â Â Â return { Â Â Â Â Â Â name: '', Â Â Â Â } Â Â }, } </script>
- Compose a label and selectable HTML list bound to the data prop
language
usingv-model
inside of the template area:    <div class="form">       <label>         Name         <input type="text" v-model="name" />       </label>       <label>         Preferred javascript style         <select name="language" v-model="language">           <option value="Javascript">JavaScript</option>           <option value="TypeScript">TypeScript</option>           <option value="CoffeeScript">CoffeeScript</option>           <option value="Dart">Dart</option>         </select>       </label>     </div>
- Finish binding the select input by returning a reactive data prop called
language
in the<script>
tag:<script> export default { Â Â data() { Â Â Â Â return { Â Â Â Â Â Â name: '', Â Â Â Â Â Â language: '', Â Â Â Â } Â Â }, } </script>
- Below the form fields, output the name and language inside of an unordered list structure (
<ul>
and<li>
) by using curly braces, for example,{{ name }}
:Note
Wrap the form and the display area within another tag such as a
<section>
tag, as only one HTML element can be at the root of a template.Your code should look as follows:
<template>   <section>     <div class="form">       <label>         Name         <input type="text" v-model="name" />       </label>       <label>         Preferred javascript style         <select name="language" v-model="language">           <option value="Javascript">JavaScript</option>           <option value="TypeScript">TypeScript</option>           <option value="CoffeeScript">CoffeeScript</option>           <option value="Dart">Dart</option>         </select>       </label>     </div>     <ul class="overview">       <li><strong>Overview</strong></li>       <li>Name: {{ name }}</li>       <li>Preference: {{ language }}</li>     </ul>   </section> </template>
- Add styling inside the
<style>
tag at the bottom of the component, and set thelang
attribute toscss
:
Exercise1-07.vue
37Â <style lang="scss"> 38Â .form { 39Â Â Â display: flex; 40Â Â Â justify-content: space-evenly; 41Â Â Â max-width: 800px; 42Â Â Â padding: 40px 20px; 43Â Â Â border-radius: 10px; 44Â Â Â margin: 0 auto; 45Â Â Â background: #ececec; 46Â } 47 48Â .overview { 49Â Â Â display: flex; 50Â Â Â flex-direction: column; 51Â Â Â justify-content: space-evenly; 52Â Â Â max-width: 300px; 53Â Â Â margin: 40px auto; 54Â Â Â padding: 40px 20px; 55Â Â Â border-radius: 10px; 56Â Â Â border: 1px solid #ececec; 57 58Â Â Â > li { 59Â Â Â Â Â list-style: none; 60Â Â Â Â Â + li { 61Â Â Â Â Â Â Â margin-top: 20px; 62Â Â Â Â Â } 63Â Â Â } 64Â } 65Â </style>
The complete code for this step is available at https://packt.live/36NiNXH.
Your output should look as follows:
Your form should look something like this. When you update the data in the form, it should also update the overview area synchronously.
In this exercise, we used the v-model
directive to bind the name and JavaScript-style drop-down selection to our local state's data. When you change the data, it will reactively update the DOM elements we output this bound data to.