I have an extensive form and I'm trying to organize this so that it remains practicable for the plan that I intend to have with it.
An example showing what my form looks like:
<input type="text" name="data[0][name]">
<input type="email" name="data[0][email]">
<input type="tel" name="data[0][phone]">
<input type="text" name="data[1][name]">
<input type="email" name="data[1][email]">
<input type="tel" name="data[1][phone]">
I want this to return as:
- data
- data[0]
- data[name]
- data[email]
- data[phone]
- data[1]
- data[name]
- data[email]
- data[phone]
But with new FormData(form);
and then Object.fromEntries(formData)
I'm just getting it on separate lines (as one large array).
Can someone help me with an easy way of converting these in a dynamic way because in my actual setup I have dozens of fields. So manually is not a desired option for me.
Thanks!
CodePudding user response:
I do not think there is a standard way to do this. You can try to find existing solution that turns FormData into JSON (https://www.google.com/search?q=formdata to json npm), you can refer to solutions from How to convert FormData (HTML5 object) to JSON, or you can find inspiration e.g. in https://github.com/therealparmesh/object-to-formdata and write reverse operation. The complexity of your solution will depend on the complexity of your data and required performance for the solution.
CodePudding user response:
To convert a (single layer) NodeList of form elements into a nested object, using the form element name components, you can loop over the data form elements:
const dataform_obj = {} // instantiate empty object
// specify regular expression to capture name components
// for example: data[0][email]
const dataform_re = /^([^\[] )(\[\d \])(\[[^\]] \])$/;
// convert form elements into array then loop
[...document.querySelector('#dataform').elements].forEach(function (elem) {
// capture name components
const match = elem.name.match(dataform_re);
// match[1] is first name, match[2] is index, match[3] is last name
// for example, ["data", "0", "email"]
// instantiate sub-objects if do not exist
if ( !dataform_obj[match[1]] ) {
dataform_obj[match[1]] = {};
}
if ( !dataform_obj[match[1]][match[1] match[2]] ) {
dataform_obj[match[1]][match[1] match[2]] = {};
}
// assign element value to object
dataform_obj[match[1]][match[1] match[2]][match[1] match[3]] = elem.value;
})
Above, a javascript regular expression is used to capture the various components of the form element name. Those components are then used to build the object hierarchy.
console.log(dataform_obj);
...produces:
data: {
data[0]: {
data[email]: "",
data[name]: "",
data[phone]: ""
},
data[1]: {
data[email]: "",
data[name]: "",
data[phone]: ""
}
Online example: https://jsfiddle.net/n4m32wzh/
Perhaps, this is the format you're actually looking for:
data: {
0: {
email: "",
name: "",
phone: ""
},
1: {
email: "",
name: "",
phone: ""
}
}
Do that like this:
const dataform_obj = {};
const dataform_re = /^([^\[] )\[(\d )\]\[([^\]] )\]$/;
[...document.querySelector('#dataform').elements].forEach(function (elem) {
const match = elem.name.match(dataform_re)
if ( !dataform_obj[match[1]] ) {
dataform_obj[match[1]] = {}; // this can alternatively be an array using [] instead of {}
}
if ( !dataform_obj[match[1]][match[2]] ) {
dataform_obj[match[1]][match[2]] = {};
}
dataform_obj[match[1]][match[2]][match[3]] = elem.value;
});
console.log(dataform_obj["data"])
Online example: https://jsfiddle.net/gnav6qb4/2/