How to use model directive with two-way computed property in Vue.js?

Shivansh Tiwari
4 min readMar 16, 2022
vue js

What is the v-model directive in Vue.js?

If you are a Vue.js developer like me, you must have heard about the very interesting v-model directive.

The v-model directive is a very useful and clean approach for both binding any changes to a value and listening for the changes that affect that value. Or in technical words, you can say v-model is a powerful directive provided by VueJS to add two-way data binding in vanilla Vue.js.

Implementing the v-model Directive with a computed property

Before starting with the implementation of the V-model, we have to understand the under-hood working of the V-model directive.

While v-model=”dataProperty” seems like magic at first glance, it’s actually a shorthand for the

<input :value="dataProperty" @input=dataProperty = $event.target.value" />

By default, the v-model is assessed every time the input event is fired (i.e. on key-down or paste). If you want to wait until the user has finished typing and blurred the input field (click outside of the input field), you can use the lazy modifier over the v-model.

<input v-model.lazy="value" />

In CoustomSearchInput.vue file, create a custom component that accepts props — value, optionsArr and placeholderValue.

<template>
<div class="container">
<input ref="inputField" v-model="inputVal" class="val-input" type="text" :placeholder="placeholderValue />
<!-- options Dropdown --><div class="data-options" v-if="filterOptionArray.length > 0" :class="{ 'd-none': openFlag }" >
<div ref="dataDiv" class="general-modal-scroll-bar">
<li
v-for="option in filterOptionArray"
:key="option"
class="item"
@click=" inputVal = option;
$emit('input', option); " >
{{ option }}
</li>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SearchInput",
props: {
optionsArr: {
type: Array,
default: () => [],
},
value: {
type: String,
default: "",
},
placeholderValue: {
type: String,
default: "",
},
},
data() {
return {
inputVal: "",
openFlag: true,
};
},
mounted() {
this.inputVal = this.value;
// Closing the options panel on load of the component
document.addEventListener("click", this.close);
},
beforeDestroy() {
// Closing the options panel on leaving the component
document.removeEventListener("click", this.close);
},
// this computed property is responsible for the fitering the array according input value
computed: {
filterOptionArray() {
if (this.inputVal.length === 0) {
return this.optionsArr;
} else {
return this.optionsArr.filter((option) => {
let temp = option.toLowerCase();
return temp.match(this.inputVal);
});
}
},
},
// keep a watch on inputVal if it's value change then we close the options Panel
watch: {
inputVal(newVal) {
this.openFlag = false;
},
},
methods: {
// Options Panel close method
close(e) {
if (
e.target !== this.$refs.dataDiv &&
e.target !== this.$refs.inputField
) {
this.openFlag = true;
}
},
},
};
</script>

So we are getting the value as a prop, from the parent component. As per the Vue 2 design pattern, we were not allowed to manipulate the prop data directly. To resolve this, we are creating a local data property inputVal and storing the value props data in inputVal, and after that, we are binding inputVal to the input field.

Now, we are creating a computed property filterOptionArray, which is responsible for the options available to select from the dropdown, depending upon the user input. This computed property returns an array, which we use to display the drop-down list.

When a user clicks on any drop-down list item, it emits an event to inform its parent about the changes.

In Parent component- App.js file.

<template>
<div id="app">
<CustomSearchInput
:optionsArr="arr"
v-model="selected"
placeholderValue="Enter start typing to get options"
/>
<div class="display-data" v-if="selected.length > 0" >Selected Value: {{ selected }}</div>
</div>
</template>
<script>
import CustomSearchInput from "./components/CoustomSearchInput";
export default {
name: "App",
components: { CustomSearchInput },
data() {
return {
arr: ["jhon", "jay", "shiv", "jani", "shawn", "shelly", "bob", "carry", "Alex", "Anthoney" ],
selected: "",
};
},
};
</script>

Play with code here

We can use this method to combine computed properties and the v-model in order to write the most robust and best code in Vue.js.

Add-on Notes:

  • If you’d like to cast user input to a number instead of a string, add the v-model.number modifier.
  • The v-model.trim modifier will strip leading or trailing whitespace from the bound string. (can not be used in conjunction with v-model.number).

About Myself:

I am a software Engineer in a fast-growing tech company Geekyants. I’m a proactive learner passionate about doing something good in the field of Full-Stack development. Currently, I’m working with JavaScript, Vue.js, and Nuxt.js.

Feel Free to connect with me:
LinkedIn
Github

Thanks, Keep Coding

--

--

Shivansh Tiwari

Vue Js Developer, Nuxt Js Developer, Software Engineer