Last active
September 23, 2021 16:04
-
-
Save dkebler/0e2559126f77cc063578843c834c59cb to your computer and use it in GitHub Desktop.
Vue dynamic/reactive nested/deep property setting and getting with vuex store
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vue from 'vue' | |
import Vuex from 'vuex' | |
import { setProp, getProp } from 'vue-properties' | |
import traverse from 'traverse' | |
import isPlainObj from 'is-plain-object' | |
Vue.use(Vuex) | |
const store = new Vuex.Store({ | |
state: { | |
}, | |
getters: { | |
get: state => { | |
return args => { | |
let path, rootPath | |
if (Array.isArray(args)) [path, rootPath] = args | |
else path = args | |
if (path) { | |
if (typeof path === 'string') path = path.split(/[./]/) | |
path = rootPath ? (path.unshift(typeof rootPath === 'string' ? rootPath.split(/[./]/) : rootPath)) : path | |
let value = getProp(state, path) | |
if (value == null) { // make non-existent prop reactive so later changes will be so | |
store.commit('set', [path, false, rootPath]) | |
value = getProp(state, path) | |
} | |
return value | |
} | |
} | |
}, | |
}, | |
mutations: { | |
set: (state, args = []) => { | |
let path, value, object, rootPath | |
if (Array.isArray(args)) [path, value, rootPath] = args | |
else ({path, value, object, rootPath} = args) | |
// if path is object or object passed, traverse and set all leaf props of object into store | |
if (object || isPlainObj(path)) { | |
// does not support rootPath | |
traverse(object || path).forEach(initLeaf) | |
} else { | |
// else update a single value | |
if (path) { | |
if (typeof path === 'string') path = path.split(/[./]/) | |
path = rootPath ? (path.unshift(typeof rootPath === 'string' ? rootPath.split(/[./]/) : rootPath)) : path | |
setProp(state, path, value) | |
} | |
} | |
function initLeaf (rootPath) { | |
if (this.isLeaf) { | |
store.commit('set', [this.path, this.node]) | |
} | |
} | |
} | |
} | |
export default store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vue from 'vue' | |
function setProp (obj, path, value, first = true) { | |
let props | |
if (first) { | |
// covert props/path from dot/slash string or avoid mutation of a passed path/props array | |
props = typeof path === 'string' ? path.split(/[./]/) : [...path] | |
} else props = path | |
const prop = props.shift() | |
if (!obj[prop]) { | |
Vue.set(obj, prop, {}) | |
} | |
if (!props.length) { | |
if (value && typeof value === 'object' && !Array.isArray(value)) { | |
obj[prop] = { ...obj[prop], ...value } | |
} else { | |
obj[prop] = value | |
} | |
return | |
} | |
setProp(obj[prop], props, value, false) | |
} | |
function getProp (obj, path, first = true) { | |
let props | |
if (first) { | |
props = typeof path === 'string' ? path.split(/[./]/) : [...path] | |
} else props = path | |
const prop = props.shift() | |
if (!obj[prop] || !props.length) { | |
return obj[prop] | |
} | |
return getProp(obj[prop], props, false) | |
} | |
function delProp (obj, path, first = true) { | |
let props | |
if (first) { | |
props = typeof path === 'string' ? path.split(/[./]/) : [...path] | |
} else props = path | |
const prop = props.shift() | |
if (!obj[prop]) { | |
return | |
} | |
if (!props.length) { | |
Vue.delete(obj, prop) | |
return | |
} | |
delProp(obj[prop], props, false) | |
} | |
export default { | |
getProp: getProp, | |
setProp: setProp, | |
delProp: delProp | |
} | |
export { setProp, getProp, delProp } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment