ANOTHER Sync in Vue 2.x with Mixin
by asemahle
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.js"></script>
<div id="app">
<div v-for="(title, index) in titles">
<p>Value in parent: {{title.title}}</p>
<custom-component :value_sync="'titles[' + index + '].title'"></custom-component>
<button v-on:click="title.title = 'Changed From Parent!'">
CHANGE FROM PARENT
</button>
</div>
</div>
<template id="custom-component">
<div>
<p>Value in child: {{value}}</p>
<button v-on:click="value = 'Changed From Child!'">
CHANGE FROM CHILD
</button>
</div>
</template>
JavaScript
var Syncify = function(vueSettings) {
//synced properties are managed within the component as computed properties
if (vueSettings.computed == null) vueSettings.computed = {};
//get all prop names
var propNames = [];
if (vueSettings.props == null) vueSettings.props = [];
if (Object.prototype.toString.call( vueSettings.props ) === '[object Array]')
propNames = vueSettings.props;
if (Object.prototype.toString.call( vueSettings.props ) === '[object Object]')
propNames = _.keys(vueSettings.props);
//only keep prop names that end in '_sync'
propNames = propNames.filter((e) => { return e.endsWith('_sync'); });
//add a computed property for each syncable prop
for (let propName of propNames) {
//get <THIS-PART>_sync. (e.g., propName == cow_sync, then dataName == cow)
dataName = propName.slice(0, -5);
//do not override manually written setters/getters
if (dataName in vueSettings.computed) continue;
//set up computed property (setters and getters) referencing $parent
vueSettings.computed[dataName] = {
get: function() { return _.get(this.$parent, this[propName]); },
set: function(v){ _.set(this.$parent, this[propName], v); },
};
}
//return modified settings
return vueSettings;
}
Vue.component('custom-component', Syncify({
template: '#custom-component',
props: ['value_sync'],
}));
var app = new Vue({
el: '#app',
data: {
titles: [
{ title: '1' },
{ title: '2' },
{ title: '3' },
]
}
});