From 20a4d90d5db6c1e78e3db8e5416928d7bcbccf18 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Sat, 23 Jul 2022 15:46:46 -0400 Subject: [PATCH] Allow setFieldValue to accept a dotted path ... e.g. you can do setFieldValue('replicator.1.foo', 'bar') to update the foo field on the second replicator set to bar This uses the eventual underscore 'set' method from https://github.com/jashkenas/underscore/pull/2961. Once it's merged we can call the method directly and not need to include these files. --- resources/js/bootstrap/globals.js | 5 +++ resources/js/bootstrap/set.js | 37 +++++++++++++++++++ resources/js/components/publish/Container.vue | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 resources/js/bootstrap/set.js diff --git a/resources/js/bootstrap/globals.js b/resources/js/bootstrap/globals.js index a1516c273d..528d8ec8fe 100644 --- a/resources/js/bootstrap/globals.js +++ b/resources/js/bootstrap/globals.js @@ -1,5 +1,6 @@ import { marked } from 'marked'; import { translate, translateChoice } from '../translations/translator'; +import { default as set } from './set'; export function cp_url(url) { url = Statamic.$config.get('cpUrl') + '/' + url; @@ -34,6 +35,10 @@ export function data_get(obj, path, fallback=null) { return value !== undefined ? value : fallback; }; +export function data_set(obj, path, value) { + set(obj, path.split('.'), value); +} + export function clone(value) { if (value === undefined) return undefined; diff --git a/resources/js/bootstrap/set.js b/resources/js/bootstrap/set.js new file mode 100644 index 0000000000..a135ad7834 --- /dev/null +++ b/resources/js/bootstrap/set.js @@ -0,0 +1,37 @@ +import isObject from 'underscore/modules/isObject.js'; +import toPath from 'underscore/modules/_toPath.js'; +import contains from 'underscore/modules/contains.js'; + + +var arrayIndex = /^\d+$/; + +// Internal function of `set`. +function deepSet(obj, path, value) { + var key = path[0]; + + if (path.length === 1) { + obj[key] = value; + return; + } + + if (!isObject(obj[key])) { + var nextKey = path[1]; + obj[key] = arrayIndex.test(nextKey) ? [] : {}; + } + + return deepSet(obj[key], path.slice(1), value); +} + +// Set the value on `path` of `object`. +// If any property in `path` does not exist it will be created. +// Returns mutated object (`obj`). +export default function set(obj, path, value) { + path = toPath(path); + + if (!isObject(obj) || !path.length) return obj; + if (contains(path, '__proto__')) throw new Error('Prototype assignment attempted'); + + deepSet(obj, path, value); + + return obj; +} diff --git a/resources/js/components/publish/Container.vue b/resources/js/components/publish/Container.vue index fbfd50faba..4faade5aea 100644 --- a/resources/js/components/publish/Container.vue +++ b/resources/js/components/publish/Container.vue @@ -111,7 +111,7 @@ export default { mutations: { setFieldValue(state, payload) { const { handle, value } = payload; - state.values[handle] = value; + data_set(state.values, handle, value); }, setValues(state, values) { state.values = values;