Use HTML input 'name' attribute to yield an Object - javascript

In ExpressJS using body-parser, there exists the functionality to parse as a JavaScript object (or JSON, I'm not entirely sure) a set of input elements which have the same name attribute with defined keys.
HTML (e.g.):
<input type="text" class="name" name="name[foo]" placeholder="input1"/>
<input type="text" class="name" name="name[bar]" placeholder="input2"/>
JavaScript (e.g.):
var obj = req.body.name;
The object obj is understood by JavaScript to be { "foo" : input1, "bar" : input2 }
I am trying to get similar functionality using standard jQuery to handle several related form inputs. What I have tried so far—to no avail—is the following:
$(".name") yields an Object containing the literal HTML (not helpful for grabbing the key-value pairs).
$(".name").map(function () {return $(this).val();}).get(); yields an array of values, but no keys.
$("input[name='name']") and $("input[name='name[]']") yield nothing.
I have also tried the following to convert the inputs to an array, but it still does not serve the purpose of pulling the information from the form as a JavaScript object/JSON:
$.fn.inputsToArray = function () {
var values= [];
$.each(this, function (i, field) {
values.push(field.value);
});
return values;
};
Is there a way to accomplish what I am trying to do without NodeJS / body-parser?
Solution:
Thanks to gaetanoM's excellent solution (accepted below), I was able to create a generic jQuery function that can be called on any jQuery object (obviously, it'll only work properly if the element is in the <input ... name="example[key]" ... /> format, but I digress).
The function is called thusly:
var output = $(":input[name^=example]").inputsToObject();
The function is defined as the following:
$.fn.inputsToObject = function () {
var values = {};
values = $(this).get().reduce(function (acc, ele) {
var key = ele.name.match(/\[(.*)\]$/)[1];
acc[key] = $(ele).val();
return acc;
}, {})
return values;
}

For the first you need $(':input[name^=name]') in order to select all input fields having the name attribute starting with name. With .get() you transform the jQuery result into an array on which you can apply .reduce():
var result = $(':input[name^=name]').get().reduce(function(acc, ele) {
var key = ele.name.match(/\[(.*)\]$/)[1]; // get the key
acc[key] = ele.getAttribute('placeholder'); // add to retval
return acc;
}, {});
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="name" name="name[foo]" placeholder="input1"/>
<input type="text" class="name" name="name[bar]" placeholder="input2"/>

Related

How to send HTML form values to localstorage in JSON string using JavaScript

what is the easiest way to retrieve form values to send to localStorage as a JSON string? I started a function with a for loop but am stuck..any nudges are greatly appreciated(still very new to this) No JQuery please. Thank you
<input type="submit" name="submit" value="submitOrder" onclick="return getValues();">
var userOrder='';
function getValues(){
for(var i=0; i < document.forms[0].length - 1; i++){
console.log(document.forms[0][i]);
return false;
}
}
localStorage.setItem('userOrder',JSON.stringify(userOrder));
console.log(localStorage.getItem('userOrder'));
You could do it like this:
html:
<form id="myform">
<input type="text" name="test">
<input type="submit" value="submitOrder">
</form>
js:
const userOrder = {};
function getValues(e) {
// turn form elements object into an array
const elements = Array.prototype.slice.call(e.target.elements);
// go over the array storing input name & value pairs
elements.forEach((el) => {
if (el.type !== "submit") {
userOrder[el.name] = el.value;
}
});
// finally save to localStorage
localStorage.setItem('userOrder', JSON.stringify(userOrder));
}
document.getElementById("myform").addEventListener("submit", getValues);
No need for jQuery. This uses ES 2015 syntax but if you need to support old browsers just run it through babel.
// Iterate over all the forms in the document as an array,
// the [...stuff] turns the nodelist into a real array
let userdata = [...document.forms].map(form => {
// iterate over all the relevant elements in the form and
// create key/value pairs for the name/object
return [...form.elements].reduce((obj, el) => {
// Every form control should have a name attribute
obj[el.name] = el.value;
return obj;
}, {});
});
// convert the data object to a JSON string and store it
localStorage.setItem('userOrder', JSON.stringify(userdata));
// pull it pack out and parse it back into an object
let data = JSON.parse(localStorage.getItem('userOrder'));
If the forms all have ids (and they should) you could also use reduce in the outer layer instead of map and hash on the form id:
let userdata = [...document.forms].reduce((result, frm) => {
result[frm.id] = [...frm.elements].reduce((obj, el) => {
and so on.

Convert dynamic list object in form to JSON with javascript

I have a form submission script that converts form inputs to JSON and submits with ajax. It works for the simple forms that I have used it for previously, but when I try to use it for lists it is not read correctly.
Inside the form there is a dynamic list of inputs that is generated by another script. The list items look like this:
<li><input type="checkbox" name="skill_list[]" value="10155"></li>
The function that reads the form looks like this:
var formToJSON = elements => [].reduce.call(elements, (data, element) => {
data[element.name] = element.value;
return data;
}, {});
Inside the event listener for the submit button, the function is called:
var data = formToJSON(this.elements);
And finally, before submission, the data is stringified:
var data = JSON.stringify(data);
The error occurs in the formToJSON function. Instead of creating an object with the name skill_list and a value like {10155, 10288, 10240} it creates an object with the name skill_list[] and the value is whatever the first value in the list is.
I've been trying to rewrite the function to recognize a list but I haven't been able to and I'm running out of ideas. Can someone please help guide me in the right direction?
PS. I would prefer to write this without jQuery.
You have to handle array of elements separately:
var formToJSON = elements => [].reduce.call(elements, (data, element) => {
var isArray = element.name.endsWith('[]');
var name = element.name.replace('[]', '');
data[name] = isArray ? (data[name] || []).concat(element.value) : element.value;
return data;
}, {});
If you want to convert form data into json object, try the following
var formData = JSON.parse(JSON.stringify($('#frm').serializeArray()));

store array into localstorage instead of replace

I'm using local storage as below like
var post = {
title: 'abc',
price: 'USD5'
};
window.localStorage['book'] = JSON.stringify(post);
I want to create nested json in my localstorage, if above code is within a click event for the user to click save, it will delete the old data and replace it. How to push new value as an array object?
Use an actual array, e.g. on page load:
var posts = JSON.parse(localStorage['book'] || "[]");
Then as you're working with it, add to the array in memory:
posts.push({
title: 'abc',
price: 'USD5'
});
Any time you want to save the value back to local storage:
localStorage['book'] = JSON.stringify(posts);
Here's a complete functional example (live copy; sadly, Stack Snippets disallow local storage):
HTML:
<div>
<label>
Name:
<input type="text" id="txt-name">
</label>
</div>
<div>
<label>
Price:
<input type="text" id="txt-price">
</label>
</div>
<div>
<input type="button" value="Add" id="btn-add">
</div>
<div id="list"></div>
JavaScript (must be after the HTML in the document):
(function() {
var nameField = document.getElementById("txt-name"),
priceField = document.getElementById("txt-price");
// On page load, get the current set or a blank array
var list = JSON.parse(localStorage.getItem("list") || "[]");
// Show the entries
list.forEach(showItem);
// "Add" button handler
document.getElementById("btn-add").addEventListener(
"click",
function() {
// Get the name and price
var item = {
name: nameField.value,
price: priceField.value
};
// Add to the list
list.push(item);
// Display it
showItem(item);
// Update local storage
localStorage.setItem("list", JSON.stringify(list));
},
false
);
// Function for showing an item
function showItem(item) {
var div = document.createElement('div');
div.innerHTML =
"Name: " + escapeHTML(item.name) +
", price: " + escapeHTML(item.price);
document.getElementById("list").appendChild(div);
}
// Function for escaping HTML in the string
function escapeHTML(str) {
return str.replace(/&/g, "&").replace(/</g, "<");
}
})();
Side note: If there's any chance at all you might have to support your code on older browsers that don't have local storage at some point, you can give yourself the option of using a polyfill that writes to cookies if you use the more verbose .getItem(...)/.setItem(..., ...) API, as they can be polyfilled whereas accessing via [] as in the above can't be.
localStorage supports strings. You should use JSONs stringify() and parse() methods.
If I understood the question and what you are looking for is storing an array and not just an object with properties.
As scunliffe commented, What you can do in order to add items to an array which is stored in the local storage is:
Generating the array with first object:
var array = [];
array[0] = //Whatever;
localStorage["array"] = JSON.stringify(array);
Adding items to the array:
//Adding new object
var storedArray = JSON.parse(localStorage["array"]);
sotreadArray.push(//Whatever);
localStorage["array"] = JSON.stringify(array);
This way you store an JSON object representing an array.
As mentioned in this post
You can also extend the default storage-objects to handle arrays and objects by:
Storage.prototype.setObj = function(key, obj) {
return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
return JSON.parse(this.getItem(key))
}

How to build a json object with a loop?

I'm trying to loop through a number of items, and create a json object. Each loop should be a new item on the object, but I'm having some issues doing it. It seems that only one set of items gets added, instead of multiple ones.
Here is my code:
jsonObj = {}
rows.each(function (index) {
jsonObj["id"] = $this.find('.elementOne').val();
jsonObj["name"] = $this.find('.elementTwo').text();
});
Here is what my json looks like:
{
id: "3"
name: "Stuff"
},
Here is what I am trying to do:
{
id: "1"
name: "Stuff"
},
{
id: "2"
name: "Stuff"
},
{
id: "3"
name: "Stuff"
}
There is no JSON here. Please don't confuse:
A JavaScript object (a data structure)
A JavaScript object literal (code to create such a data structure)
JSON (a data format based on a subset of object literal notation)
If you want an ordered list of objects (or any other kind of JavaScript data structure) then use an array. Arrays have a push method.
var myData = [];
rows.each(function (index) {
var obj = {
id: $this.find('.elementOne').val(),
name: $this.find('.elementTwo').text()
};
myData.push(obj);
});
You override the object instead of adding it a new value each iteration.
Fixed code using an array:
jsonObj = [];
rows.each(function(index) {
jsonObj.push({
'id': $this.find('.elementOne').val(),
'name': $this.find('.elementTwo').text()
});
});​
What you want is an array of objects. When you try to write the same property on the same object multiple times, it gets overwritten which is why you're seeing id and name contain values for the last iteration of the loop.
Although you haven't tagged the question with jQuery, it does look like jQuery, so here's a solution:
I've taken the liberty to change $this to this because $this seems to be referring to the same object in each iteration, which is now what you may want (methinks)
var myArray = rows.map(function() {
return {
id: $(this).find('.elementOne').val(),
name: $(this).find('.elementTwo').text()
};
});
You can do it like this with jquery. The function will expect form elements of type input. It will iterate over thr passed form and it will collect each input name and value and it will create a json object like
Exmple:
HTML
<form action="" method="post" id="myForm">
<input type="text" name="field1" value="I am value of field 1"/>
<input type="text" name="field2" value="I am value of field 2"/>
</form>
Javascript
function buildObject(form) {
var jsonObject = [],
tempObj = {};
$(form).find("input:not(input[type='submit'])").each(function() {
tempObj[$(this).attr("name")] = $(this).val();
});
jsonObject.push(tempObj);
return jsonObject[0];
}
buildObject($("#myForm"));
//Will produce
jsonObj = {
field1 : "I am value of field 1",
field2 : "I am value of field 2"
}
This is because you're merely overwriting the same properties of your object, id and name, each time. You need to be making a sub-object for each, then push it into the master object (which I've converted to array, since it's non-associative).
var jsonObj = []
rows.each(function (index) {
var temp_obj = {};
temp_obj["id"] = $this.find('.elementOne').val();
temp_obj["name"] = $this.find('.elementTwo').text();
jsonObj.push(temp_obj);
});
[EDIT] - as Mark Eirich's answer shows, the temp_obj is unnecessary - you could push an anonymous object instead, but I defined temp_obj just to make it crystal clear what's happening.
Also read Quentin's very good points re: common confusion between JavaScript objects and JSON.
var jsonObj = [];
rows.each(function(index) {
jsonObj.push({
id: $this.find('.elementOne').val(),
name: $this.find('.elementTwo').text()
});
});

How to convert jQuery.serialize() data to JSON object?

Is there any better solution to convert a form data that is already serialized by jQuery function serialize(), when the form contains multiple input Array fields. I want to be able to convert the form data in to a JSON object to recreate some other informative tables. So tell me a better way to get the serialize string converted as a JSON object.
<form id='sampleform'>
<input name='MyName' type='text' /> // Raf
<!--array input fields below-->
<input name='friendname[]' type='text' /> // Bily
<input name='fiendemail[]' type='text' /> // bily#someemail.com
<!--duplicated fields below to add more friends -->
<input name='friendname[]' type='text' /> // Andy
<input name='fiendemail[]' type='text' /> // Andy#somwhere.com
<input name='friendname[]' type='text' /> // Adam
<input name='fiendemail[]' type='text' /> // Adam#herenthere.com
</form>
The jquery method applied to get the data
var MyForm = $("#sampleform").serialize();
/** result : MyName=Raf&friendname[]=Billy&fiendemail[]=bily#someemail.com&friendname[]=Andy&fiendemail[]=Andy#somwhere.com&friendname[]=Adam&fiendemail[]=Adam#herenthere.com
*/
how do I make this data in to a JSON object?
which should have the following example JSON data from the above form.
{
"MyName":"raf",
"friendname":[
{"0":"Bily"},
{"1":"Andy"},
{"2":"Adam"}
],
"friendemail":[
{"0":"bily#someemail.com"},
{"1":"Andy#somwhere.com"},
{"2":"Adam#herenthere.com"}
]
}
var formdata = $("#myform").serializeArray();
var data = {};
$(formdata ).each(function(index, obj){
data[obj.name] = obj.value;
});
Simple and fast ;)
I have recently had this exact problem. Initially, we were using jQuery's serializeArray() method, but that does not include form elements that are disabled. We will often disable form elements that are "sync'd" to other sources on the page, but we still need to include the data in our serialized object. So serializeArray() is out. We used the :input selector to get all input elements (both enabled and disabled) in a given container, and then $.map() to create our object.
var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
var o = {};
o[n.name] = $(n).val();
return o;
});
console.log(obj);
Note that for this to work, each of your inputs will need a name attribute, which will be the name of the property of the resulting object.
That is actually slightly modified from what we used. We needed to create an object that was structured as a .NET IDictionary, so we used this: (I provide it here in case it's useful)
var obj = $.map(inputs, function(n, i)
{
return { Key: n.name, Value: $(n).val() };
});
console.log(obj);
I like both of these solutions, because they are simple uses of the $.map() function, and you have complete control over your selector (so, which elements you end up including in your resulting object). Also, no extra plugin required. Plain old jQuery.
Use the jQuery.serializeJSON plugin.
It converts forms using the same format as what you would find in a Rails params object, which is very standard and well tested.
I'm using this very little jQuery plugin, that I've extended from DocumentCloud:
https://github.com/documentcloud/documentcloud/blob/master/public/javascripts/lib/jquery_extensions.js
It is basically two lines of code, but it requires _.js (Underscore.js), since it is based on a reduce function.
$.fn.extend({
serializeJSON: function(exclude) {
exclude || (exclude = []);
return _.reduce(this.serializeArray(), function(hash, pair) {
pair.value && !(pair.name in exclude) && (hash[pair.name] = pair.value);
return hash;
}, {});
}
});
Extensions:
It doesn't serialize an input value if it's null
It can exclude some inputs by passing an array of input names to the exclude argument i.e. ["password_confirm"]
I think there're a lot of good answer here, and I made my own function based on these answers.
function formToJSON(f) {
var fd = $(f).serializeArray();
var d = {};
$(fd).each(function() {
if (d[this.name] !== undefined){
if (!Array.isArray(d[this.name])) {
d[this.name] = [d[this.name]];
}
d[this.name].push(this.value);
}else{
d[this.name] = this.value;
}
});
return d;
}
//The way to use it :
$('#myForm').submit(function(){
var datas = formToJSON(this);
return false;
});
Well let me explain basically why I prefer this solution...
If you have multiples input with the same name, all values will be stored in an Array but if not, the value will be stored directly as the value of the index in the JSON ... This is where it's different from Danilo Colasso's answer where the JSON returned is only based of array values...
So if you have a Form with a textarea named content and multiples authors, this function will return to you :
{
content : 'This is The Content',
authors :
[
0: 'me',
1: 'you',
2: 'him',
]
}
An equivalent solution to Danilo Colasso's, with the sames pros and cons of .serializeArray() (basically it uses .reduce instead of $.each).
With little effort it allows implementing the extra features in S.C.'s answers without requiring extensions.
$(selector).serializeArray()
.reduce(function(accum, item) {
// This 'if' allows ignoring some values
if (-1 === [ 'ignoreThis', 'andThat' ].indexOf(item.name)) {
// This allows ignoring NULL values
if (item.value !== null) {
accum[item.name] = item.value;
}
}
return accum;
},
{
// By supplying some initial values, we can add defaults
// for, say, disabled form controls.
preFilledName: preFilledValue, // optional
defaultName : defaultValue // optional
}
);
if you can use ES6, you could do
const obj = arr.reduce((acc, {name, value}) => ({...acc, [name]: value}), {})
for a serialized array works very well.
var formdata = $("#myform").serializeArray();
var data = {};
$(formdata ).each(function(index, obj){
if(data[obj.name] === undefined)
data[obj.name] = [];
data[obj.name].push(obj.value);
});
Using underscore & jQuery
var formdata = $("#myform").serializeArray();
var data = {};
_.each(formdata, function(element){
// Return all of the values of the object's properties.
var value = _.values(element);
// name : value
data[value[0]] = value[1];
});
console.log(data); //Example => {name:"alex",lastname:"amador"}
Using the power of reducing function!
$(form).serializeArray().reduce(function (output, value) {
output[value.name] = value.value
return output
}, {})
With all Given Answer there some problem which is...
If input name as array like name[key], but it will generate like this
name:{
key : value
}
For Example :
If i have form like this.
<form>
<input name="name" value="value" >
<input name="name1[key1]" value="value1" >
<input name="name2[key2]" value="value2" >
<input name="name3[key3]" value="value3" >
</form>
Then It will Generate Object like this with all given Answer.
Object {
name : 'value',
name1[key1] : 'value1',
name2[key2] : 'value2',
name3[key3] : 'value3',
}
But it have to Generate like below,anyone want to get like this as below.
Object {
name : 'value',
name1 : {
key1 : 'value1'
},
name2 : {
key2 : 'value2'
},
name3 : {
key2 : 'value2'
}
}
Then Try this below js code.
(function($) {
$.fn.getForm2obj = function() {
var _ = {};
$.map(this.serializeArray(), function(n) {
const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
if (keys.length > 1) {
let tmp = _;
pop = keys.pop();
for (let i = 0; i < keys.length, j = keys[i]; i++) {
tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
}
if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
else tmp[pop] = n.value;
} else _[keys.pop()] = n.value;
});
return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
console.clear();
console.log($('form').getForm2obj());
});
})(jQuery);
console.log($('form').getForm2obj());
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
<input name="name" value="value">
<input name="name1[key1]" value="value1">
<input name="name2[key2]" value="value2">
<input name="name3[key3]" value="value3">
<input type="checkbox" name="name4[]" value="1" checked="checked">
<input type="checkbox" name="name4[]" value="2">
<input type="checkbox" name="name4[]" value="3">
</form>
if you are using ajax requests then no need to make it json-object only $('#sampleform').serialize() works excellently or if you have another purpose here is my solution:
var formserializeArray = $("#sampleform").serializeArray();
var jsonObj = {};
jQuery.map(formserializeArray , function (n, i) {
jsonObj[n.name] = n.value;
});
Use JSON.stringify() and serializeArray():
console.log(JSON.stringify($('#sampleform').serializeArray()));

Categories