const Parse = require("parse-self-host")
const get = require('lodash/get')
const set = require('lodash/set')
const clone = require('lodash/clone')
const Vue = require('vue@2.6.12')
// instead of obj.set, use setPath, so that we can use Vue's internals to set the data reactively
Parse.Object.prototype.setPath = function setPath (key, val) {
const paths = key.split('.')
if (paths.length === 1) {
// use vue's internals to set reactivity on the _data object set inside a Parse.Object instance
// strip away frozen-ness of the attribute, in case val is an object
Vue.set(this._data, key, clone(val))
return this.set(key, val)
}
const rootKey = paths.shift()
const root = get(this.attributes, rootKey) || {}
set(root, paths, clone(val))
Vue.set(this._data, rootKey, root) // same, see as above - I set the root key in case the rootKey doesn't exist, and you're trying to set data nested within that - can cause problems with reactivity in Vue, this is safer
return this.set(rootKey, root)
}
// create a new class from extended Parse.Object prototype
class Meal extends Parse.Object {
constructor () {
super('Meal')
Vue.set(this, '_data', {}) // reactive setter, sets our base data object
}
}
const meal = new Meal ()
meal.setPath('label', 'Potatoes') // reactively set on _data.label
meal.setPath('category', 'Dinner') // reactively set on _data.category
const vue = new Vue({
data () {
return {
// bind the Parse.Object to the vue instance so the ui updates when the reactive data changes
meal: meal
// note: using meal.attributes in the UI is NOT reactive because its a frozen object
// note: using {{ meal.get('label') }} in the UI template won't update because Vue doesn't know to re-call the #get function so no updates here either
}
},
// this is only here to test the assertion that the UI will update when the data changes, the two are equivalent
watch: {
// this watcher will fire anytime anything in the meal._data changes
// and log the contents of the entire _data object
'meal._data': {
deep: true,
handler (val) {
console.log('watch:_data', val)
}
},
// this watcher only watches for the label property
// updates here are equivalent to changes to {{ meal._data.label }} in the ui template
'meal._data.label' (val, oldVal) {
console.log('watch:_data.label', val, oldVal)
}
}
})
// manually update by calling the setter (eg on select item from a select input)
// meal.setPath('category', 'Breakfast')
// auto real-time updates to the reactive object by binding to form input control
meal._data.label = 'Toast'