vue-vmodel-mapper
is a small helper to simplify the creation of custom v-model components that accept an object type as value prop.
It's quite complicated to create custom v-model components that behave correctly, especially if they accept a prop object.
The prop cannot be mutated and component must emit a new object on change of any value in the object.
You also can't conveniently bind to nested values in prop object using v-model
directive since it mutates as well.
vue-vmodel-mapper
generates the boilerplate to setup a custom v-model component painlessly by mapping keys in the prop object to computed variables that can detect change and emit a new object with the changes.
npm i --save vue-vmodel-mapper
<template>
<input v-model="firstname" />
<input v-model="lastname" />
</template>
<script>
import vueVmodelMapper from 'vue-vmodel-mapper';
export default {
name: 'CustomVmodel',
prop: {
// value is an object with { firstname, lastname }
value: {
type: Object
}
},
computed: {
// key name for every key in prop object
...vueVmodelMapper(['firstname', 'lastname'])
}
}
</script>
vue-vmodel-mapper
takes two arguments, an array of keys to map into computed variables and an optional customisation object.
Without second argument, vue-vmodel-mapper
defaults the v-model prop name to value
, and changes will emit event name input
.
Pass a second argument to vue-vmodel-mapper
to customize prop and event name to match names used by your component
<template>
<input v-model="firstname" />
<input v-model="lastname" />
</template>
<script>
import vueVmodelMapper from 'vue-vmodel-mapper';
export default {
name: 'CustomVmodel',
model: {
prop: 'customKeyName',
event: 'customEventName'
},
prop: {
// value is an object with { firstname, lastname }
value: {
type: Object
}
},
computed: {
...vueVmodelMapper(
['firstname', 'lastname'],
{
prop: 'customKeyName',
event: 'customEventName'
}
)
}
}
</script>
Create computed variables for every key in this.value
with separate get and set functions.
Setting a computed variable will trigger an emit of a new object instead of mutating the existing this.value
prop.
vue-vmodel-mapper
is just a helper generates the computed variables below.
<template>
<input v-model="firstname">
<input v-model="lastname">
</template>
<script>
export default {
name: 'CustomVmodel',
prop: {
value: {
type: Object
}
},
// boilerplate generated by vue-vmodel-mapper
computed: {
firstname: {
get() {
return this.value.firstname;
},
// setter to emit new object on change of firstname
set(newValue) {
this.$emit('input', {
...this.value,
firstname: newValue,
});
}
},
lastname: {
get() {
return this.value.lastname;
},
// setter to emit new object on change of lastname
set(newValue) {
this.$emit('input', {
...this.value,
lastname: newValue,
});
}
}
}
}
</script>
It assumes values for the object keys mapped are primitive types like String
, Number
or Boolean
. It cannot detect changes in nested objects.
eg:
// can't detect changes to innerkey1
const prop = {
key1: 'hello',
key2: {
innerkey1: 'world'
}
}
npm i
npm test
npm run test:watch