How does one create, collect and programmatically (one entry per form-element) aggregate objects from related form-elements?
Solution 1:
The most flexible approach does not make any assumptions about a form's inner DOM hierarchy. It instead would focus on the naming schema which all form-element's name
attributes have in common, and which is ... "t-<key>-<id>"
.
Thus an entirely DOM-structure agnostic but partially re-usable approach would be bipartite / two-folded.
-
The first part does introduce the regex upon which any form-element will be identified. This regex is as follows ...
/^t-(?<key>\w+)-(?<id>\d+)$/
. It features named groups for capturing aname
value'skey
andid
part. The actual task ...-
transforms the form elements collection into an array
-
filter
s all valid (according to the regex) form elements. -
reduce
s the filtered array into a list ofdataItems
-
The reducer function gets provided the regex as part of a config object which is passed as initial value to
reduce
as well.
-
-
The second task is implemented as generic and re-usable function which creates and stores
dataItem
objects upon a form element's extractedid
as well as this element's extractedkey
and itsvalue
.
function collectDataItemsByElementKeyAndId(collector, elmNode) {
const { regX, list, map } = collector;
const { key, id } = regX.exec(elmNode.name)?.groups ?? {};
let dataItem = map[id];
if (!dataItem) {
dataItem = map[id] = {};
list.push(dataItem);
}
Object.assign(dataItem, { [key]: elmNode.value });
return collector;
}
function handleSubmit(evt) {
evt.preventDefault();
const regXKeyAndId = /^t-(?<key>\w+)-(?<id>\d+)$/;
const dataItemList = Array
.from(this.elements) // `this` refers to the form element.
.filter(elm => regXKeyAndId.test(elm.name))
.reduce(collectDataItemsByElementKeyAndId, {
regX: regXKeyAndId,
map: {},
list: [],
}).list;
console.log({ dataItemList });
}
$('#myForm').on('submit', handleSubmit);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myForm">
<div id="parent-div">
<div>
<input type="text" style="margin: 0;" name="t-name-1" value="value1" />
<span>
<input type="text" name="t-quantity-1" value="1" />
<input type="text" name="t-frequency-1" value="6" />
</span>
</div>
<div>
<input type="text" style="margin: 0;" name="t-name-2" value="value2" />
<span>
<input type="text" name="t-quantity-2" value="2" />
<input type="text" name="t-frequency-2" value="8" />
</span>
</div>
</div>
<button type="submit">
Submit
</button>
</form>
Solution 2:
$('#myForm').on('submit', function(e) {
e.preventDefault();
var divs = document.querySelectorAll('#myForm > #parent-div > div')
var group = []
divs.forEach(div => {
var inputs = div.querySelectorAll('input')
var obj = {}
inputs.forEach(i => {
var name = i.getAttribute('name').split('-')[1]
obj[name] = i.value
})
group.push(obj)
})
console.log(group)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myForm">
<div id="parent-div">
<div>
<input type="text" style="margin: 0;" name="t-name-1" value="value1" />
<span>
<input type="text" name="t-quantity-1" value="1" />
<input type="text" name="t-frequency-1" value="6" />
</span>
</div>
<div>
<input type="text" style="margin: 0;" name="t-name-2" value="value2" />
<span>
<input type="text" name="t-quantity-2" value="2" />
<input type="text" name="t-frequency-2" value="8" />
</span>
</div>
</div>
<button type="submit">
Submit
</button>
</form>