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>

<div id="app">
  <p>
    Value in parent: {{title}}
  </p>
  <custom-component :value_sync="title" v-on:value-change="title = arguments[0]"></custom-component>
  <button v-on:click="title = 'Changed From Parent!'">CHANGE FROM PARENT</button>
</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 SyncMixin = {
  created: function () {
    for (let propName of this.$options._propKeys) {
      // only sync props ending with '_sync'
      if (!propName.endsWith('_sync')) continue;
      dataName = propName.slice(0, propName.length - 5);
      
      //only sync props if there's matching data 
      if (!(dataName in this.$data)) continue;
      
      //initially set data equal to prop
      this.$data[dataName] = this[propName];
      
      // reset data to prop when prop changes
      this.$watch(propName, (newVal, oldVal) => {
      	this.$data[dataName] = this[propName];
      });
      
      // emit changed event when data changes
      this.$watch(dataName, (newVal, oldVal) => {
      	this.$emit(dataName + '-change', newVal);
      });
    }
  },
}

Vue.component('custom-component', {
  template: '#custom-component',
  mixins: [SyncMixin],
  props: ['value_sync'],
  data: function() {
  	return {
    	value: null,
    }
  }
});



var app = new Vue({
    el: '#app',
    data: {
        title: 'Original Value',
    }
});