I'm trying to receive value as separate object array for each element.
This is my code
<input class="name" name="name[]" type="text" />
<input class="date_of_birth" name="DoB[]" type="text" />
<input class="age" type="radio" name="age" value="1" />
<input class="age" type="radio" name="age" value="0" />
var kidName = [];
$(".name").each(function() {
kidName.push($(this).val());
});
var newDob = [];
$(".date_of_birth").each(function() {
newDob.push($(this).val());
});
var age = [];
$(".age:checked").each(function() {
age.push($(this).val());
});
var kids = {
"kidName": kidName,
"newDob": newDob,
"age": age
};
How i get the value with this as separate array for each element.
kids: {
kidName: ["Test1", "Test2"]
newDob: ["20/02/2000", "20/03/2018"]
age: ["19", "1"]
}
But i want to receive these values like this
kids:
{
kidName: ["Test1"],
newDob: ["20/02/2000"],
age: ["19"]
},
{
kidName: ["Test2"],
newDob: ["20/03/2018"],
age: ["1"]
}
How can i achieve this, what changes should i make to receive values like this?
Thanks
One option is to put the form group into a container. Select the container and use map to loop thru the containers. In this example, the container is a div with class input-group
Note: you need to change the name of radio button every container.
var result = $(".input-group").map(function() {
return {
kidName: $(this).find('.name').val(),
newDob: $(this).find('.date_of_birth').val(),
age: $(this).find('.age:checked').val(),
}
}).get();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="input-group">
<input class="name" name="name[]" type="text" value="Test1" />
<input class="date_of_birth" name="DoB[]" type="text" value="20/02/2000" />
<input class="age" type="radio" name="age01[]" value="1" checked/>
<input class="age" type="radio" name="age01[]" value="0" />
</div>
<div class="input-group">
<input class="name" name="name[]" type="text" value="Test2" />
<input class="date_of_birth" name="DoB[]" type="text" value="20/03/2018" />
<input class="age" type="radio" name="age02[]" value="1" />
<input class="age" type="radio" name="age02[]" value="0" checked/>
</div>
Based on what is present in your question, the best I can suggest is just to reformat the data you have into the format you need.
Id you're able to provide your html, it may be possible to get the data into this format initially rather than reparsing it.
const kids = {
kidName: ["Test1", "Test2"],
newDob: ["20/02/2000", "20/03/2018"],
age: ["19", "1"],
};
const kidsArraysToObjects = kids => kids.kidName.map(
(_, i) => Object.keys(kids).reduce((prev, curr) => ({
...prev,
[curr]: kids[curr][i]
}), {})
)
const result = kidsArraysToObjects(kids)
console.dir(result)
Here is what i have tried
var kids = []
$(".name").each(function(index, value) {
if (kids[index] == undefined) {
kids[index] = {}
}
kids[index].kidName = $(this).val()
});
$(".date_of_birth").each(function(index, value) {
if (kids[index] == undefined) {
kids[index] = obj
}
kids[index].newDob = $(this).val()
});
$(".age:checked").each(function(index, value) {
if (kids[index] == undefined) {
kids[index] = obj
}
kids[index].age = $(this).val()
});
NOTE: I haven't tested this
try this replace parent-selector-each-record with common class or id of each row
by using this approach you get exact data. also you can use #OliverRadini approach
var kids = [];
$("parent-selector-each-record").each(function() {
var kid = {};
kid["kidName"] = $(this).find(".name").val()
kid["newDob"] = $(this).find(".date_of_birth").val()
kid["age"] = $(this).find(".age:checked").val()
kids.push(kid);
});
I also suggest to reformat your object structure after that you get the data, since it will avoid some coupling with your HTML. In other words, it avoids to touch your JavaScript when you want to change your HTML.
const kids = {
kidName: ["Test1", "Test2"],
newDob: ["20/02/2000", "20/03/2018"],
age: ["19", "1"]
}
const keys = Object.keys(kids);
const result = kids[keys[0]].map((_, i) => {
return keys.reduce((obj, key) => {
obj[key] = kids[key][i];
return obj;
}, {});
});
console.log(result);
Related
I have a function that takes elements from the DOM to update a db on button click. Currently, there is one id for one value...
<input class='total' doc-id='12345678' value='${whateverCurrent.value}'>user updates</field>
<input class='total' doc-id='87654321' value='${whateverCurrent.value}'>user updates</field>
This is the function:
const elements = document.querySelectorAll('.total')
await Promise.all(Array.from(elements).map(async (el) => {
let docId = el.id;
let total = el.value;
await updateDoc(docId, { total });
}))
I now need to break this down such that there are 4 classes of input fields rather than 1 (by quarter). So there will be different elements but with the same id:
<input class='q1' doc-id='12345678' value='${whateverCurrent.value}'>user updates</field>
<input class='q2' doc-id='87654321' value='${whateverCurrent.value}'>user updates</field>
<input class='q2' doc-id='12345678' value='${whateverCurrent.value}'>user updates</field>
I could run the Promise.all function 4 times, once for each class, but that must be wrong, when instead I should somehow....
// (do something here){
await updateDoc(docId, {q1, q2, q3, q4})
}
when I take all the elements and put them into an array and look at them in the console, I get an array of 4 NodeLists.
How do I take these 4 nodeLists and amalgamate them so that every id has its 4 values to pass to the update function?
I'm not really sure if this is what you're looking for. Can you be more specific in what the updateDoc function expects as arguments?
Anyway, I coded something that collects all the quarterly values per doc-id and produces an object of following form:
{
1234 :
{
q1 : 7
q2 : 9
},
...
}
const elements = document.querySelectorAll('input')
const docsPerQ = {};
elements.forEach(e => {
const docId = e.getAttribute('doc-id');
const val = e.value;
const quarter = e.className;
if(!(docId in docsPerQ)) docsPerQ[docId] = {};
docsPerQ[docId][quarter] = val;
});
console.log(docsPerQ);
<input type="text" class="q1" value="7" doc-id="1234">
<input type="text" class="q1" value="2" doc-id="5678">
<input type="text" class="q2" value="3" doc-id="5678">
<input type="text" class="q2" value="9" doc-id="1234">
EDIT
I changed the code a bit so the produced output is in a more manageable form. It's now an array of objects with some extra keys attached:
[
{
docId: 1234,
quarters: {
q1: 7,
q2: 3
}
},
...
]
const elements = document.querySelectorAll('input');
const QsPerDoc = [];
elements.forEach(e => {
const docId = e.getAttribute('doc-id');
const val = e.value;
const quarter = e.className;
const entry = QsPerDoc.find(e => e.docId === docId);
// find returns undefined if nothing's found. undefined is a falsy value
if(!entry) {
let quarters = {};
quarters[quarter] = val;
QsPerDoc.push({
docId : docId,
quarters
});
}
else {
entry.quarters[quarter] = val;
}
});
console.log(QsPerDoc);
<input type="text" class="q1" value="7" doc-id="1234">
<input type="text" class="q1" value="2" doc-id="5678">
<input type="text" class="q2" value="3" doc-id="5678">
<input type="text" class="q2" value="9" doc-id="1234">
Maybe this works better? Hope it does. I wonder, is the updateDoc function something you can change so it can accept arrays?
You could access them like this:
console.log(QsPerDoc[0].docId);
console.log(QsPerDoc[0].quarters.q1);
(Note: I also changed the name of the object/array to QsPerDoc instead of DocsPerQ, which was not aplty named)
Anyway I have to get back to work instead of procrastinating on stackoverflow ;)
I am trying to write a function in jQuery.
var arr1 = ["Jcob", "Pete", "Fin", "John"];
var str = $("#fname").val();
if (jQuery.inArray(str, arr1))
$("#lname").text("Bob");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="fname" name="fname">
<input type="text" id="lname" name="lname">
Please check my fiddle here
What it will do it the user will give the value in the first input box the jQuery function will check if the value is present in that array it will fill the second input box with the given text.
Three things:
You need to add an event listener to the first input to constantly keep checking when someone inputs something.
Before selecting elements in the DOM, make sure the DOM is ready.
You don't need jQuery at all here. Like most things, very easy to do without jQuery.
const names = [ "Jcob", "Pete", "Fin", "John" ];
document.addEventListener('DOMContentLoaded', function() {
const fname = document.getElementById('fname');
const lname = document.getElementById('lname');
fname.addEventListener('input', function(event) {
lname.value = names.includes(fname.value) ? 'Bob' : '';
});
});
<input type="text" id="fname" name="fname">
<input type="text" id="lname" name="lname">
If you insist on jQuery (which I do strongly recommend you shouldn't until you are proficient with the native DOM API):
const names = [ "Jcob", "Pete", "Fin", "John" ];
$(document).ready(function() {
const $fname = $('#fname');
const $lname = $('#lname');
$fname.on('input', function(event) {
if ($.inArray($fname.val(), names) > -1) {
$lname.val('Bob');
} else {
$lname.val('');
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="fname" name="fname">
<input type="text" id="lname" name="lname">
Try this:
<body>
<input type="text" id="fname" name="fname">
<input type="text" id="lname" name="lname">
<button onclick="checkValue()">Click</button>
<script>
var arr1 = ["Jcob", "Pete", "Fin", "John"];
function checkValue() {
var str = $("#fname").val();
var val = jQuery.inArray(str, arr1);
if (val === -1) {
console.log("no value");
}
else {
$("#lname").val("Bob");
}
}
</script>
</body>
So, let's say I have an HTML form like this:
<form id="myForm">
<input type="text" name="dummy">
<input type="text" name="people[0][first_name]" value="John">
<input type="text" name="people[0][last_name]" value="Doe">
<input type="text" name="people[1][first_name]" value="Jane">
<input type="text" name="people[1][last_name]" value="Smith">
</form>
And I want to get a JavaScript array that matches the values of real. For example:
// If there was a sweet function for this...
var people = getFormDataByInputName( 'people' );
// Value of `people` is...
// [
// {
// 'first_name' : 'John',
// 'last_name' : 'Doe'
// },
// {
// 'first_name' : 'Jane',
// 'last_name' : 'Smith'
// }
// ]
Is there any easy way of doing that for just a specific form item (in this case, people)? Or would I have to serialize the entire form an then just extract the element I want?
I also thought of potentially using the following approach:
var formData = new FormData( document.querySelector( '#myForm' ) );
var people = formData.get( 'people' );
But that doesn't appear to work; people is just null after that.
You could do this with plain js using reduce method and return each person is one object.
const form = document.querySelectorAll('#myForm input');
const data = [...form].reduce(function(r, e) {
const [i, prop] = e.name.split(/\[(.*?)\]/g).slice(1).filter(Boolean)
if (!r[i]) r[i] = {}
r[i][prop] = e.value
return r;
}, [])
console.log(data)
<form id="myForm">
<input type="text" name="dummy">
<input type="text" name="people[0][first_name]" value="John">
<input type="text" name="people[0][last_name]" value="Doe">
<input type="text" name="people[1][first_name]" value="Jane">
<input type="text" name="people[1][last_name]" value="Smith">
</form>
function getObject(name, key) {
if(key.includes(name)) {
var splitStr = key.split(/\[|\]/g);
return {
index: splitStr[1],
key: splitStr[3],
}
}
return null;
}
function getFormDataByInputName(name) {
var formData = new FormData( document.querySelector('#myForm'));
var results = [];
for (var key of formData.keys()) {
var obj = getObject(name, key);
if (obj) {
if (results[obj.index]) results[obj.index][obj.key] = formData.get(key);
else results[obj.index] = { [obj.key]: formData.get(key) };
}
}
return results;
}
var people = getFormDataByInputName('people');
console.log(people);
<form id="myForm">
<input type="text" name="dummy">
<input type="text" name="people[0][first_name]" value="John">
<input type="text" name="people[0][last_name]" value="Doe">
<input type="text" name="people[1][first_name]" value="Jane">
<input type="text" name="people[1][last_name]" value="Smith">
</form>
Your code won't work because to HTML/JS name is just a string that it sends to the server when the form is submitted (the name in the name/value pairs). You might think it is arrays, but HTML/JS doesn't.
So no one-liner to get the job done. Try this: In your HTML, add <div class="name"> ...
(UPDATE: thanks for the idea, #Nenad, I've never tried one of these snippets)
var people = [];
$('.name').each(function() {
people.push({
first_name: $('input:nth-child(1)', this).val(),
last_name: $('input:nth-child(2)', this).val()
});
});
console.log(people);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="myForm">
<input type="text" name="dummy">
<div class="name">
<input type="text" value="John">
<input type="text" value="Doe">
</div>
<div class="name">
<input type="text" value="Jane">
<input type="text" value="Smith">
</div>
</form>
Use CSS attribute prefix selector, such as
form.querySelectorAll('[name^="people[]"]')
You can use a for-loop to get all peoples, as such
const MAX_PEOPLES = 2;
const list = [];
for (i = 0; i <= MAX_PEOPLES; i++) {
const eles = form.querySelectorAll(`[name^="people[${i}]`);
if (eles.length !== 2)
break;
list.push({
first_name: eles[0].value,
last_name: eles[1].value
});
}
that yields
[
{
"first_name":"John",
"last_name":"Doe"
},
{
"first_name":"Jane",
"last_name":"Smith"
}
]
I am currently getting data from a repeatable group form through serializeArray() as an object with this syntax:
group_field[0][address]:"street one"
group_field[0][number]:"10000"
group_field[0][city]:"nyc"
group_field[1][address]:"street two"
group_field[1][number]:"600"
group_field[1][city]:"washington"
group_field[2][address]:"street three"
group_field[2][number]:"34000"
group_field[2][city]:"paris"
I am trying to convert this to a multidimensional array, or nested object structure to group all the fields depending on the index between the first square brackets.
desired output:
group_fields = [
"0": {
"address": "street one",
"number": "10000",
"city": "nyc",
},
"1": {
"address": "street two",
"number": "600",
"city": "washington",
},
"2": {
"address": "street three",
"number": "34000",
"city": "paris",
},
}
I have tried several things, I will write the last point i got to after alot of different unsuccessful methods:
var values = {};
var params = {};
$.each(theForm.serializeArray(), function(i, field) {
values[field.name] = decodeURIComponent(field.value);
});
for (var key in values){
if (values.hasOwnProperty(key)) {
var matches = key.match(/[^[\]]+(?=])/g);
if(matches != null && matches.length > 0) {
var index = matches[0];
var theKey = matches[1];
var theVal = values[key];
var single = {
[theKey]: theVal,
}
params[matches[0]].push(single);
}
}
}
this obviously does not work.
Any help appreciated
What you've quoted doesn't look like the result of serializeArray, but working from what I believe your form looks like, it's not that hard. The main thing is that serializeArray returns an array of {name, value} objects, so we just have to isolate the two significant parts of the group_field names and then use those to build up our array with the objets in it. See comments:
var theForm = $("form");
// Create the array
var group_fields = [];
// Loop through the fields
theForm.serializeArray().forEach(function(entry) {
// Get the index and prop name from the entry name
var nameparts = /^group_field\[(.+)\]\[(.*)\]$/.exec(entry.name);
// Get the group entry if we already have it
var group = group_fields[nameparts[1]];
if (!group) {
// We don't, create and add it
group = group_fields[nameparts[1]] = {};
}
// Set the property (address, street, etc.)
group[nameparts[2]] = entry.value;
});
console.log(group_fields);
.as-console-wrapper {
max-height: 100% !important;
}
<form>
<input type="hidden" name="group_field[0][address]" value="street one">
<input type="hidden" name="group_field[0][number]" value="10000">
<input type="hidden" name="group_field[0][city]" value="nyc">
<input type="hidden" name="group_field[1][address]" value="street two">
<input type="hidden" name="group_field[1][number]" value="600">
<input type="hidden" name="group_field[1][city]" value="washington">
<input type="hidden" name="group_field[2][address]" value="street three">
<input type="hidden" name="group_field[2][number]" value="34000">
<input type="hidden" name="group_field[2][city]" value="paris">
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Or using ES2015+ (since you used computed property names in your original attempted solution):
const theForm = $("form");
// Create the array
const group_fields = [];
// Loop through the fields
theForm.serializeArray().forEach(entry => {
// Get the index and prop name from the entry name
const [ , index, prop] = /^group_field\[(.+)\]\[(.*)\]$/.exec(entry.name);
// Get the group entry if we already have it
var group = group_fields[index];
if (!group) {
// We don't, create and add it
group = group_fields[index] = {};
}
// Set the property (address, street, etc.)
group[prop] = entry.value;
});
console.log(group_fields);
.as-console-wrapper {
max-height: 100% !important;
}
<form>
<input type="hidden" name="group_field[0][address]" value="street one">
<input type="hidden" name="group_field[0][number]" value="10000">
<input type="hidden" name="group_field[0][city]" value="nyc">
<input type="hidden" name="group_field[1][address]" value="street two">
<input type="hidden" name="group_field[1][number]" value="600">
<input type="hidden" name="group_field[1][city]" value="washington">
<input type="hidden" name="group_field[2][address]" value="street three">
<input type="hidden" name="group_field[2][number]" value="34000">
<input type="hidden" name="group_field[2][city]" value="paris">
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I have used the struts json plugin and tried to convert the form data to json format to submit by ajax.
I have two cases in the HTML
<form>
<input type="text" name="user.name" value="Tom"></p>
<input type="text" name="user.location" value="China"></p>
<input type="text" name="user.data[0].id" value="993"></p>
<input type="text" name="user.data[0].accountId" value="123"></p>
<input type="text" name="user.data[1].id" value="222"></p>
<input type="text" name="user.data[1].accountId" value="333"></p>
</form>
What I expected is to convert it to the json structure:
{
user : {
name: "Tom",
location : "China",
data: [
{
id : 993,
accountId : 123
},
{
id : 222,
accountId : 333
}
]
}
}
I know how to declare the json data and declare the attributes one by one.
I would like to have the better way to make each form to be in json format using simple way rather than declaring the parameter one by one in json format.
Appreciate for any suggestion or advice. Thank you.
Provided your form is exactly like that
Using a plain JS approach
<form class="userform">
<input type="text" class="username" value="Tom"></p>
<input type="text" class="userlocation" value="China"></p>
<input type="text" class="userid" value="993"></p>
<input type="text" class="useraccountid" value="123"></p>
<input type="text" class="userid2" value="222"></p>
<input type="text" class="useraccountid2" value="333"></p>
</form>
Then assign the values to the object
var frm = document.getElementsByClassName('userform');
//initialize blank object and keys
var user = {},
user.name = "",
user.location = "",
user.data = [];
//get all child input elements
for(var i = 0; i < frm.length; i++){
var uname = frm[i].getElementsByClassName('username')[0];
var uloc = frm[i].getElementsByClassName('userlocation')[0];
var uid = frm[i].getElementsByClassName('userid')[0];
var uaccid = frm[i].getElementsByClassName('useraccountid')[0];
var uid = frm[i].getElementsByClassName('userid2')[0];
var uaccid = frm[i].getElementsByClassName('useraccountid2')[0];
//assign values to object here
user[name] = {}; //assigning a parent property here, the name for example.
user[name].name = uname.value;
user[name].location = uloc.value;
user[name].data.push({
'id': uid.value
'accountId': uaccid.value
});
user[name].data.push({
'id': uid2.value
'accountId': uaccid2.value
});
}
JSON.stringify(user); //convert to JSON (or ignore if you want a plain object)
Output would be this in JSON format
{
user :{
Tom: {
name: "Tom",
data: [
{
id : 993,
accountId : 123
},
{
id : 222,
accountId : 333
}
]
},
Jerry: {
//more data
},
Courage: {
//more data
}
}
}
Hope this helps
If your input fields are many, like id3, accountid3, 4, 5, 6. You have to loop through the classes that you assign to these two repetitive fields
Here you go with a solution using jQuery https://jsfiddle.net/pnz8zrLx/2/
var json = {};
$('button').click(function(){
$('form').each(function(i){
json["user" + i] = {};
json["user" + i].data = [];
var tempJSON = {};
$('form:nth-child(' + (i+1) + ') input[type="text"]').each(function(){
if($(this).attr('name') === 'name' || $(this).attr('name') === 'location'){
json["user" + i][$(this).attr('name')] = $(this).val();
} else {
tempJSON[$(this).attr('name')] = $(this).val();
if(tempJSON != {} && $(this).attr('name') === 'accountId'){
json["user" + i].data.push(tempJSON);
tempJSON = {};
}
}
});
});
console.log(json);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<input type="text" name="name" value="Tom">
<input type="text" name="location" value="China">
<input type="text" name="id" value="993">
<input type="text" name="accountId" value="123">
<input type="text" name="id" value="222">
<input type="text" name="accountId" value="333">
</form>
<form>
<input type="text" name="name" value="Test">
<input type="text" name="location" value="Test112">
<input type="text" name="id" value="22">
<input type="text" name="accountId" value="78">
<input type="text" name="id" value="00">
<input type="text" name="accountId" value="44">
</form>
<button>
Submit
</button>
Hope this will help you.