Last active
April 30, 2021 12:46
-
-
Save digitalWestie/db3821bc608f5877a9cc284dcfc42aba to your computer and use it in GitHub Desktop.
JSON Object to form builder
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
const insertInput = (name, value, type, labelText) => { | |
// Create wrapper for input and label | |
const inputWrapper = document.createElement("div"); | |
// Create label and input | |
let label = document.createElement("label"); | |
let content = document.createTextNode(labelText); | |
let input = document.createElement("input"); | |
input.setAttribute('type', type); | |
input.setAttribute('name', name); | |
input.setAttribute('value', value); | |
input.setAttribute('class', 'object-input'); | |
label.appendChild(content); | |
label.appendChild(input); | |
inputWrapper.appendChild(label); | |
return inputWrapper; | |
}; | |
const removeInputs = (event) => { | |
event.target.parentElement.remove(); | |
}; | |
const addInputs = (event) => { | |
let prefix = event.target.parentElement.parentElement.getAttribute("data-property"); | |
let name = new Date - 0; | |
//prefixedName = [prefix + "[]", name].filter(x => x).join("_"); | |
prefixedName = [prefix, name].filter(x => x).join("_"); | |
let wrapper = document.createElement("fieldset"); | |
wrapper.setAttribute("class", "wrapper"); | |
wrapper.setAttribute("data-property", prefixedName); | |
let removeBtn = document.createElement("button"); | |
removeBtn.appendChild(document.createTextNode("Remove")); | |
removeBtn.setAttribute("type", "button"); | |
removeBtn.addEventListener('click', removeInputs); | |
wrapper.appendChild(removeBtn); | |
let fieldName = [prefixedName, "url"].filter(x => x).join("_"); | |
wrapper.appendChild(insertInput(fieldName, '', 'url', "url")); | |
fieldName = [prefixedName, "title"].filter(x => x).join("_"); | |
wrapper.appendChild(insertInput(fieldName, '', 'text', "title")); | |
event.target.parentElement.parentElement.appendChild(wrapper); | |
}; | |
const insertInputs = (targetElement, data, prefix, addCb, removeCb) => { | |
let result, value, prefixedName, isCollection, target; | |
let isArrayElement = (Array.isArray(data)); | |
for (name of Object.keys(data)) { | |
value = data[name]; | |
//if (isArrayElement) { prefix = prefix + "[]"; } | |
prefixedName = [prefix, name].filter(x => x).join("_"); | |
isCollection = (typeof value === 'object' && value !== null); | |
needsWrapper = (isArrayElement || isCollection); | |
target = targetElement; | |
if (needsWrapper) { | |
let wrapper = document.createElement("fieldset"); | |
wrapper.setAttribute("class", "wrapper"); | |
wrapper.setAttribute("data-property", prefixedName); | |
targetElement.appendChild(wrapper); | |
target = wrapper; | |
if (isArrayElement){ | |
let removeBtn = document.createElement("button"); | |
removeBtn.appendChild(document.createTextNode("Remove")); | |
removeBtn.setAttribute("type", "button"); | |
removeBtn.addEventListener('click', removeInputs); | |
target.appendChild(removeBtn); | |
} | |
} | |
if (isCollection) { | |
if (!isArrayElement) { | |
//Provide a heading for the following object | |
let subheading = document.createElement("legend"); | |
subheading.appendChild(document.createTextNode(name)); | |
target.appendChild(subheading); | |
if (Array.isArray(value)){ | |
// This collection is an array, insert an add button | |
let addBtn = document.createElement("button"); | |
addBtn.appendChild(document.createTextNode("Add")); | |
addBtn.setAttribute("type", "button"); | |
addBtn.addEventListener('click', addCb); | |
subheading.appendChild(addBtn); | |
} | |
} | |
insertInputs(target, value, prefixedName, addCb, removeCb); | |
} else { | |
if (isArrayElement) { name = ""; } | |
result = insertInput(prefixedName, value, 'text', name); | |
target.appendChild(result); | |
} | |
} | |
} | |
const unflatten = (data) => { | |
// unflattens flat objects like | |
// { "data_links_123230_title": "mytitle" } | |
// into | |
// { "data": "links": [{"title": "mytitle"}] } | |
let result = {} | |
let keys, lastGroup, thisGroup; | |
for (var i in data) { | |
keys = i.split('_'); | |
thisGroup = keys.filter((k, i) => { return (i !== keys.length-1) }); // all but last thing | |
thisGroup = thisGroup.join("_"); | |
keys.reduce(function(r, e, j) { | |
if (Array.isArray(r) && !isNaN(Number(e))) { //is an array element | |
e = r.length; //renumber to maintain index in order | |
if (lastGroup === thisGroup) { e--; } // is not a new element, select last | |
} | |
return (r[e]) || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 == j ? data[i] : {}) : []); | |
}, result); | |
lastGroup = thisGroup; | |
} | |
return result | |
} | |
const collectInputsIntoObject = () => { | |
let inputs = document.querySelectorAll("textarea.object-input, input.object-input"); | |
let data = {}; | |
for (input of inputs){ | |
data[input.getAttribute('name')] = input.value; | |
} | |
return unflatten(data); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
insertInputs(document.getElementById('my-form-id'), { "foo": [{ "bar": "xyz" }] }, "data", addInputs, removeInputs);