convert object with string array keys - javascript

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>

Related

Double Square Brackets in my Javascrip Arrays within localStorage?

I have managed to get data registering to my localStorage as arrays, however I have three queries:
Why are there double square brackets around my array?
How do I change the name field to the respective html ID?
Data returning as undefined when I try to retrieve it from the localStorage?
The output I am looking for in my localStorage is:
bookings: [
[0]{fname: "John", lname: "Smith" }
[1]{fname: "Jane", lname: "Doe" }
]
But I am currently getting:
bookings: [
[0][{name: "fname" value: "John"},{name: "lname": value: "Smith" }]
[1][{name: "fname" value: "Jane"},{name: "lname": value: "Doe" }]
]
I understand how to change the name value when items are hardcoded but I am initialising an empty array in my JS and not sure where the error is, I have tried assigning a value to the array [0] but then it doesn't register anything. I have also tried the data.flat() method which does nothing.
The issue is my next step is to amend and delete items so I need to try and understand the structure. Currently I am getting undefined when I try to get data from storage, I have provided my remove function (currently to show) below, I know it is wrong but I think the issue is to do with how I am storing the data. Sorry I have asked so many questions on this but I am new to JS and still learning. I am struggling with searches as there are so many variations of Javascript and getting a lot of answers relating to C# or Python which isn't helping.
Here is my code:
//var bookings = [];
var bookings = localStorage.getItem("bookings");
$("#submit").click(function () {
//bookings = JSON.parse(localStorage.getItem("bookings")) || [];
bookings = (bookings) ? JSON.parse(bookings) : [];
var newBooking = $("#regForm").serializeArray();
bookings.push(newBooking)
var json = JSON.stringify(bookings);
const newData = bookings.flat();
window.localStorage.setItem("bookings", json);
});
$("#remove").click(function () {
var strBookings;
var i;
strBookings = localStorage.getItem("bookings");
//document.write("<p>" + strBookings + "</p>");
bookings = JSON.parse(strBookings);
for (i = 0; i < strBookings.length; i++) {
document.write("<p>" + strBookings[i].value + "</p>");
}
//localStorage.removeItem('bookings');
});
Form
<form id="regForm" name="regForm" class="col-sm-6">
<div class="row">
<input type="text" id="fname" placeholder="First Name" name="fname" required>
<input type="text" id="lname" placeholder="Last Name" name="lname" required>
<input id="submit" type="submit" value="Submit">
</div>
</form>
Show
//var bookings = [];
var bookings = localStorage.getItem("bookings");
$("#submit").click(function () {
//bookings = JSON.parse(localStorage.getItem("bookings")) || [];
bookings = (bookings) ? JSON.parse(bookings) : [];
var newBooking = $("#regForm").serializeArray();
bookings.push(newBooking)
var json = JSON.stringify(bookings);
const newData = bookings.flat();
window.localStorage.setItem("bookings", json);
});
$("#remove").click(function () {
var strBookings;
var i;
strBookings = localStorage.getItem("bookings");
//document.write("<p>" + strBookings + "</p>");
bookings = JSON.parse(strBookings);
for (i = 0; i < strBookings.length; i++) {
document.write("<p>" + strBookings[i].value + "</p>");
}
//localStorage.removeItem('bookings');
});
<form id="regForm" name="regForm" class="col-sm-6">
<div class="row">
<input type="text" id="fname" placeholder="First Name" name="fname" required>
<input type="text" id="lname" placeholder="Last Name" name="lname" required>
<input id="submit" type="submit" value="Submit">
</div>
</form>
<button id="remove" value="Remove">Show</button>

How to receive value as each separate object javascript

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);

How to convert the input name dot to json format in simple way?

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.

how to convert variable name into index string of object jquery

when I make a looping based on the content in the form of an input form
I'll take the attribute name to be used as a selector element and object index array of data, but the index is the variable name
how to convert from a variable name to string index on an object array
of data?
it aims to make input in the form can be filled automatically from the object array of data
var data = {
id: "4",
Model: "804",
Description: "AXIAL SETTER,100MM, MAGNETIC BASE"
};
var names = [];
if ($('#form').length == 1) {
$('#form :input').each(function() {
names.push($(this).attr('name'));
});
$.each(names, function(key, value) {
$('[name="' + value + '"]').val(data.value);
//value should be change with name,
//for example :
// $('name="Description"').val(data.Description);
});
}
<form action="#" id="form" class="form-horizontal">
<input type="hidden" name="id" />
<br/>
<input type="text" name="Model" placeholder="Model Of product" />
<br/>
<input type="text" name="Description" placeholder="Description Of product" />
<br/>
<button type="submit" class="btn-save">save</button>
</form>
No need to run twice over the same data. You could simply do this to fill your form:
var data = {
id: "4",
Model: "804",
Description: "AXIAL SETTER,100MM, MAGNETIC BASE"
};
if ($('#form').length == 1) {
$('#form :input').each(function() {
if (typeof data[$(this).attr('name')] != 'undefined'){
$(this).val(data[$(this).attr('name')]);
}
});
}
Have a look at https://jsfiddle.net/nfq22d9r/1/
The code runs through all the forms input fields, checks if a fields name is existent as a key in the data object and sets the fields value to the one in the data object, if the key was found

How can I create an array from the values of DOM elements with AngularJS?

I have a number of hidden input fields on a page. I want to read the values of these input fields into an array. The input fields have this structure:
<div class="loadedFood" ng-model="savedFood">
<div class="foodItem">
<input type="hidden" name="[food][61][uid]" value="61" />
<input type="hidden" name="[food][61][unit]" value="30.00" />
<input type="hidden" name="[food][61][quantity]" value="4" />
<input type="hidden" name="[food][61][total]" value="120" />
</div>
<div class="foodItem">
<input type="hidden" name="[food][67][uid]" value="67" />
<input type="hidden" name="[food][67][unit]" value="7.00" />
<input type="hidden" name="[food][67][quantity]" value="6" />
<input type="hidden" name="[food][67][total]" value="42" />
</div>
</div>
I want to read these into an array loadedFood with each div fooditem becoming a new array element, containing the names and values of the hidden inputs, like:
[{
uid : 61,
unit : 7.00,
quantity : 6,
total : 42,
} {
uid : 67,
unit : 3.00,
quantity : 3,
total : 42,
}]
I can push the value of each individual input on the page to the array loadedFood like this:
$scope.savedFood = angular.forEach(angular.element(".foodItem input"), function (value, key) {
var a = angular.element(value);
value = a.attr("value");
console.log(value)
$scope.loadedFood.push(value);
});
But obviously that's not what I want. I need to create a new element for each .foodItem, and then add both the name and the value of each input within it, and then push the whole element to loadedFood. I'm stuck on the very basic problem of how DOM element selectors work in AngularJS- trying to do something JQueryish like
var input = angular.element(value + " input");
totally breaks.
First of all, is doing this sort of a DOM-element-iteration too much of trying to apply a JQuery approach to Angular? Is there a better Angular method of getting what I need, which is the data in the hidden inputs in the form of the array above?
Secondly, how do you extend element selectors in AngularJS- if you have element a, how do you select for inputs contained within a?
Here's a Plunkr
If you want to make your code work, use directive.
However (I think like bekite and Davin Tryon about to check design again).
JS
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.loadedFood = [];
$scope.savedFood = function () {
$scope.savedFoodDirective();
};
});
fessmodule.$inject = ['$scope'];
fessmodule.directive('joe', function () {
return {
restrict: 'A',
link: function (scope, elm, attrs) {
var list = elm[0].getElementsByTagName('input');
angular.forEach(list, function (value, key) {
var a = angular.element(value);
a.addClass("ss");
name = a.attr("name");
val = a.attr("value");
var line = {val : val, name : name};
console.log(line)
scope.loadedFood.push(line);
});
}
};
});
Demo Fiddle
Output:
[
{
"val": "61",
"name": "[food][61][uid]"
},
{
"val": "30.00",
"name": "[food][61][unit]"
},
{
"val": "4",
"name": "[food][61][quantity]"
},
{
"val": "120",
"name": "[food][61][total]"
}
]

Categories

Resources