Skip to content

Instantly share code, notes, and snippets.

@digitalWestie
Last active April 30, 2021 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save digitalWestie/db3821bc608f5877a9cc284dcfc42aba to your computer and use it in GitHub Desktop.
Save digitalWestie/db3821bc608f5877a9cc284dcfc42aba to your computer and use it in GitHub Desktop.
JSON Object to form builder
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);
}
@digitalWestie
Copy link
Author

Usage:

insertInputs(document.getElementById('my-form-id'), { "foo": [{ "bar": "xyz" }] }, "data", addInputs, removeInputs);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment