Vue 3.4 defineModel — game changing feature!
Hey Vue enthusiasts! Vue 3 stepped onto the scene on September 18, 2020, but let’s face it — getting it into production had its challenges. Popular packages like Vuetify took their time catching up, and developers were a bit hesitant, feeling somewhat like the transition from Angular 1 to Angular 2.
Until Vue 3.3 (May 2023), Vue 3 wasn’t stealing the spotlight, but post that version, it’s been making a comeback, just like the good old days. (Between you and me, I’ve dabbled in both Vue and React, explored React for some syntax sugar, but, shh, Vue remains my preferred choice these days.)
Now, fast forward, Vue 3 has matured, dishing out some nifty syntactic sugar. While I was initially hooked on <script setup>, today, let’s dive into another gem — defineModel. Before Vue 3.4, we were juggling props, modelValue, and emitting events. But hooray! Achieving smooth two-way binding between parent and child components is now a piece of cake.
Super easy, right? How was that before?
For me, the first one is crystal clear, seriously boosting readability. Vue keeps getting better, and I’m loving the journey!
v-model
modifiers
From the original documentation, we can also use the modifiers with this new game changing feature.
When we were learning about form input bindings, we saw that v-model
has built-in modifiers - .trim
, .number
and .lazy
. In some cases, you might also want the v-model
on your custom input component to support custom modifiers.
Let’s create an example custom modifier, capitalize
, that capitalizes the first letter of the string provided by the v-model
binding:
<MyComponent v-model.capitalize="myText" />
Modifiers added to a component v-model
can be accessed in the child component by destructuring the defineModel()
return value like this:
<script setup>
const [model, modifiers] = defineModel()
console.log(modifiers) // { capitalize: true }
</script>
<template>
<input type="text" v-model="model" />
</template>
To conditionally adjust how the value should be read / written based on modifiers, we can pass get
and set
options to defineModel()
. These two options receive the value on get / set of the model ref and should return a transformed value. This is how we can use the set
option to implement the capitalize
modifier:
<script setup>
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.capitalize) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
return value
}
})
</script>
<template>
<input type="text" v-model="model" />
</template>
How we were handling this before Vue 3.4
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})
const emit = defineEmits(['update:modelValue'])
function emitValue(e) {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
<template>
<input type="text" :value="modelValue" @input="emitValue" />
</template>
For the more details:
- https://vuejs.org/guide/components/v-model.html
- https://vuejs.org/api/sfc-script-setup.html#definemodel
- https://www.youtube.com/watch?v=lJ6mUrZfbWQ (a bit older one and uses old technics)
- https://medium.com/javascript-in-plain-english/vue-3-4-is-here-definemodel-and-why-it-matters-50ead5d3d1c1
Stay tuned for more exciting Vue 3 features… Keep rocking with Vue 3! 🚀