mapPropsModel Helper
Bring together "Props Down, events up" pattern and v-model
by abernov
HTML
<script src="https://unpkg.com/vue"></script>
<div id="app">
<h4>Passing one Object as prop, and one listener to update all properties</h4>
<my-form ref="form" v-bind:data="{name, age, size}" @update="handleChange"></my-form>
<hr>
<h4>Passing properties as individual props and listening to individual updates.</h4>
<my-other-form
:name="name" :age="age" :size="size"
@name="name = $event" @age="age = $event" @size="size = $event"
></my-other-form>
<hr>
<h4>3rd Vriation: individual props, but one listener</h4>
<my-other-form2
:name="name" :age="age" :size="size"
@update="handleChange"
></my-other-form2>
<hr>
<h4>4th Variation: one Data props, multiple event listeners</h4>
<my-other-form3
:data="{ name, age, size }"
@name="name = $event" @age="age = $event" @size="size = $event"
></my-other-form3>
<pre>
{{$data}}
</pre>
</div>
<template id="my-form">
<div>
<label>Name
<input type="text" v-model="nameModel">
</label><br>
<label>Age
<input type="number" v-model.number="ageModel">
</label><br>
<label>Size
<select v-model="sizeModel">
<option v-for="option in ['S', 'M', 'L', 'XL']">{{option}}</option>
</select>
</label><br>
</div>
</template>
Babel + JSX
function mapPropsModels (props = [], {object, event} = {}) {
return props.reduce((obj, prop) => {
const propModel = prop + 'Model'
const computedProp = {
get() {
return object ? this[object][prop] : this[prop]
},
set(value) {
if (event) {
this.$emit(event, { prop, value })
} else {
this.$emit(prop, value)
}
}
}
obj[propModel] = computedProp
return obj
}, {})
}
Vue.component('my-form', {
name: 'myForm',
template: '#my-form',
props: ['data'],
computed: {
...mapPropsModels(['name', 'age', 'size'], { object: 'data', event: 'update'})
}
})
Vue.component('my-other-form', {
name: 'myOtherForm',
template: '#my-form',
props: ['name', 'age', 'size'],
computed: {
...mapPropsModels(['name', 'age', 'size'], /*{ event: 'update'}*/)
}
})
Vue.component('my-other-form2', {
name: 'myOtherForm',
template: '#my-form',
props: ['name', 'age', 'size'],
computed: {
...mapPropsModels(['name', 'age', 'size'], {event: 'update'})
}
})
Vue.component('my-other-form3', {
name: 'myOtherForm',
template: '#my-form',
props: ['data'],
computed: {
...mapPropsModels(['name', 'age', 'size'], { object: 'data'})
}
})
var app = new Vue({
el: '#app',
data: {
name: 'Tom',
age: 25,
size: 'XL'
},
methods: {
handleChange({prop, value}) {
console.log('handling...', prop, value)
this[prop] = value
}
}
})
console.log(app)