jQuery/javascript get form data just like a post array - javascript

I have an HTML form and I want to get all its data in the same structure as a $_POST would. So if I have some inputs like this:
<input type="text" name=r[1][0] value="x"><input type="text" name=r[1][1] value="y">
I would like to get and object like this:
obj = {r:{1:{0:x,1:y}}}
Can you please tell me there is any way I could do this? I tried serializeArray().. and other "custom" solutions with no success.
Thank you! :)

1 weeks ago, i had almost same problem, i developed a function which can convert input to a JavaScript object.
It's maybe more then what you need, but you can take a look in this :
var myObj = {};
function addValueToObj(objet, nom) {
var pathBrackets = "";
var regex = /\[([0-9]+)\]$/;
nom = nom.split("=");
var path = nom[0].split('.');
val = nom.slice(1).join("=");
for (var i = 0, tmp = objet; i<path.length-1; i++) {
pathBrackets += path[i]+".";
if (path[i].match(regex)!=null) {
var valindex = path[i].match(regex)[1];
var index = path[i].match(regex).index;
var newPath = path[i].substring(index, 1-path[i].length);
if (typeof tmp[newPath] == "undefined") {
tmp = tmp[newPath] = [];
tmp = tmp[valindex] = {};
} else {
if (typeof tmp[newPath][valindex] == "undefined") {
tmp = tmp[newPath][valindex] = {};
} else {
tmp = tmp[newPath][valindex];
}
}
} else {
if (typeof tmp[path[i]] == "undefined") {
tmp = tmp[path[i]] = {};
} else {
tmp = tmp[path[i]];
}
}
}
tmp[path[i]] = val;
}
$(document).ready(function() {
$.each($("input"), function() {
addValueToObj(myObj, $(this).attr('name')+"="+$(this).val());
})
console.log(myObj);
})
and the HTML :
<form>
x :<input type="text" name="r.1.0" value="x">
y :<input type="text" name="r.1.1" value="y">
</form>
Result :
{
"r":{
"1":{
"0":"x",
"1":"y"
}
}
}
Hope it can help you.
Here the JSFiddle

Related

How To Create Multiple Arrays From a Single Array?

I getting form data in my console like this:
{item[0][sku]: 'EC1000-WMK', item[0][qty]: '1', item[1][sku]: 'POP-11', item[1][qty]: '1', form_key: 'ZuQxqBMHmidjUxEt'}
form_key: "ZuQxqBMHmidjUxEt"
item[0][qty]: "1"
item[0][sku]: "EC1000-WMK"
item[1][qty]: "1"
item[1][sku]: "POP-11"
This is how the above data created:
$.fn.getFormData = function(){
var data = {};
var dataArray = $(this).serializeArray();
console.log(data);
console.log(dataArray);
for(var i=0;i<dataArray.length;i++){
console.log(dataArray);
data[dataArray[i].name] = dataArray[i].value;
}
return data;
}
but I want to make it like:
[
{ "sku": "EC1000-WMK", "qty": "1" }
{ "sku": "POP-11", "qty": "1" }
]
Use Input fields name be like
<input name="item.0.sku" />
<input name="item.0.qty" />
<input name="item.1.sku" />
<input name="item.2.qty" />
& then use this function
Here is the function which converts all form inputs to JSON format
const jsonSerialize = ($this) => {
$this = $this.find('input, select');
let data = {};
for (let i = 0; i < $this.length; i++) {
let el = $this[i];
let val = el.value;
if (!val) val = "";
let fullName = el.getAttribute("name");
if (!fullName) continue;
let fullNameParts = fullName.split('.');
let prefix = '';
let stack = data;
for (let k = 0; k < fullNameParts.length - 1; k++) {
prefix = fullNameParts[k];
if (!stack[prefix]) {
stack[prefix] = {};
}
stack = stack[prefix];
}
prefix = fullNameParts[fullNameParts.length - 1];
if (stack[prefix]) {
let newVal = stack[prefix] + ',' + val;
stack[prefix] += newVal;
} else {
stack[prefix] = val;
}
}
return data
}
let $form = $('form');
params = jsonSerialize($form)
Hope may this work for you

Get variables from URL and convert to array

I need to retrieve variables from an URL.
I use this found function:
function getParams(str) {
var match = str.replace(/%5B/g, '[').replace(/%5D/g, ']').match(/[^=&?]+\s*=\s*[^&#]*/g);
var obj = {};
for ( var i = match.length; i--; ) {
var spl = match[i].split("=");
var name = spl[0].replace("[]", "");
var value = spl[1];
obj[name] = obj[name] || [];
obj[name].push(value);
}
return obj;
}
var urlexample = "http://www.test.it/payments/?idCliente=9&idPagamenti%5B%5D=27&idPagamenti%5B%5D=26"
var me = getParams(stringa);
The output is:
{"idPagamenti":["26","27"],"idCliente":["9"]}
But idCliente is always NOT an array, so i'd like to retrieve:
{"idPagamenti":["26","27"],"idCliente": 9 }
This is the fiddle example
function getParams(str) {
var match = str.replace(/%5B/g, '[').replace(/%5D/g, ']').match(/[^=&?]+\s*=\s*[^&#]*/g);
var obj = {};
for ( var i = match.length; i--; ) {
var spl = match[i].split("=");
var name = spl[0].replace("[]", "");
var value = spl[1];
obj[name] = obj[name] || [];
obj[name].push(value);
}
return obj;
}
var stringa = "http://www.test.it/payments/?idCliente=9&idPagamenti%5B%5D=27&idPagamenti%5B%5D=26"
var me = getParams(stringa);
$(document).ready(function(){
alert("testing");
console.log(me);
$(".a").html(JSON.stringify(me));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="a">
</div>
Someone can help me to modify code?
I think your facing a real paradigm problem. Why idCliente wouldn't be an array but idPagamenti would be. You should have all array or none but not both. getParams() function can make this choice for you and you should probably change the way you are working with this.
Anyway, here is a getParams() function that replace any single-valued array to a value. Note that if you have only one idPagamenti in your URI, you will also have a single value for idPagamenti instead of an array.
function getParams(str) {
var match = str.replace(/%5B/g, '[').replace(/%5D/g, ']').match(/[^=&?]+\s*=\s*[^&#]*/g);
var obj = {};
for ( var i = match.length; i--; ) {
var spl = match[i].split("=");
var name = spl[0].replace("[]", "");
var value = spl[1];
obj[name] = obj[name] || [];
obj[name].push(value);
}
Object.keys(obj).forEach(key => {
if (obj[key].length === 1) {
obj[key] = obj[key][0];
}
})
return obj;
}
var urlexample = "http://www.test.it/payments/?idCliente=9&idPagamenti%5B%5D=27&idPagamenti%5B%5D=26"
var me = getParams(stringa);
If you know that you will always get ids as parameters, you can also add a parseInt() for each parameter by replacing var value = spl[1]; with var value = parseInt(spl[1], 10);

Loop performance converting XML to JSON in JavaScript

I am encountering a performance issue trying to fill in a grid with some data from a webservice.
Thanks to the Timeline analyzer from Chrome, I have found the function wich is causing my performance issue. It's due to a loop to get all the data from an xml and converting it into a JSON.
I've tried different loop (each, for, while) expecting improvement but didn't find better than each.
Here is an example of the xml with one child (but in my case there can be 10000 childs):
<DockDistrSearchOutput>
<groupRecord>
<uniqueIdentifier><![CDATA[KP789281]]></uniqueIdentifier>
<supplierCode><![CDATA[10003]]></supplierCode>
<supplierDescription><![CDATA[GROSFILLEX]]></supplierDescription>
<supplierCommercialContractCode><![CDATA[CTCOM01]]></supplierCommercialContractCode>
<supplierCommercialContractDescription><![CDATA[STANDARD EN EURO]]></supplierCommercialContractDescription>
<supplierAddressChainCode><![CDATA[1]]></supplierAddressChainCode>
<supplierAddressChainDescription><![CDATA[FIL1]]></supplierAddressChainDescription>
<articleCode><![CDATA[13A42001]]></articleCode>
<articleDescription><![CDATA[Banane]]></articleDescription>
<logisticVariantCode><![CDATA[2]]></logisticVariantCode>
<logisticVariantDescription><![CDATA[VL0 BANANE C G100]]></logisticVariantDescription>
<weightFactor><![CDATA[0]]></weightFactor>
<purchasePricePerKilo><![CDATA[13]]></purchasePricePerKilo>
<amount><![CDATA[0]]></amount>
<startDate><![CDATA[2016-07-29]]></startDate>
<endDate><![CDATA[2016-07-31]]></endDate>
<crossDockDiscount />
<crossDockMargin />
<extraMargin><![CDATA[3]]></extraMargin>
<listPrice />
<costPriceRD />
<oldSupplierCode><![CDATA[10003]]></oldSupplierCode>
<oldSupplierCommercialContractCode><![CDATA[CTCOM01]]></oldSupplierCommercialContractCode>
<oldSupplierAddressChainCode><![CDATA[1]]></oldSupplierAddressChainCode>
<oldArticleCode><![CDATA[13A42001]]></oldArticleCode>
<oldLogisticVariantCode><![CDATA[2]]></oldLogisticVariantCode>
<oldStartDate><![CDATA[2016-07-29]]></oldStartDate>
<oldEndDate><![CDATA[2016-07-31]]></oldEndDate>
</groupRecord>
</DockDistrSearchOutput>
And here is the loop used to get the data (15900ms for my test case) :
function getDataFromXml(xml){
var data = [];
$(xml).children().each( function (index) {
uniqueNumber++;
var recStatus = ORIGINAL;
if(this.getAttribute("recordState")!=null){
recStatus = this.getAttribute("recordState");
}
this.setAttribute("recordState", recStatus);
this.setAttribute("lineNumber", uniqueNumber);
var record = [];
if(this.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
$(this).children().each(function () {
record[this.tagName] = this.text;
});
record["recordState"] = recStatus;
record["rowXML"] = this;
data.push(record);
record = null;
recStatus = null;
});
return data;
}
Here are other try to get the data faster:
function getDataFromXml(xml){
var data = [];
$(xml).children().each( function (index) {
uniqueNumber++;
var recStatus = ORIGINAL;
if(this.getAttribute("recordState")!=null){
recStatus = this.getAttribute("recordState");
}
this.setAttribute("recordState", recStatus);
this.setAttribute("lineNumber", uniqueNumber);
var record = [];
/* First try
var a = $(this).children();
var l = a.length;
while(l--){
record[a[l].tagName] = a[l].text;
}*/
//Second try
var tmp = "{", cur = null;
for(var i =0, ln=this.childElementCount; i<ln;++i)
{
cur = this.children[i];
tmp += '"'+cur.tagName+'":"'+cur.text.replace('"', '')+'",';
}
tmp +='}';
tmp = tmp.replace(',}', '}');
record=JSON.parse(tmp);
if(this.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
record["recordState"] = recStatus;
record["rowXML"] = this;
data.push(record);
tmp = null;
cur = null;
record = null;
recStatus = null;
});
return data;
}
A try with only JavaScript (9600ms in my test case):
function getDataFromXml(xml){
var data = [];
var a = xml.getElementsByTagName("groupRecord");
var l = a.length;
while(l--){
uniqueNumber++;
var recStatus = ORIGINAL;
var groupRec = a[l];
if(groupRec.getAttribute("recordState")!=null){
recStatus = groupRec.getAttribute("recordState");
}
groupRec.setAttribute("recordState", recStatus);
groupRec.setAttribute("lineNumber", uniqueNumber);
var record = [];
var b = groupRec.childNodes;
var j = b.length;
while(j--){
record[b[j].tagName] = b[j].text;
}
if(groupRec.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
record["recordState"] = recStatus;
record["rowXML"] = groupRec;
data.push(record);
tmp = null;
cur = null;
record = null;
recStatus = null;
groupRec = null;
}
return data;
}
If someone has any advice to increase the performance of my loop?
Thanks in advance!
Edit: Thanks to Jaromanda X I have improved the performance by using only JavaScript.

Error: Cannot read property 'value' of null

I am extremely new to javascript and so I apologize in advance for any problems with the way I am asking my quesion. I am trying to post data and have a warning pop up if all fields are not filled out. And one of the fields is a radio type. Here is a link to a jsfiddle with my script http://jsfiddle.net/J2yWQ/64/
Here is what I have at the moment
function emailWarning() {
var check = document.getElementById("check");
check.className = 'show';
}
function validateEmail(xem) {
var re = /\S+#\S+\.\S+/;
return re.test(xem);
}
function postData() {
email = 'email'+document.getElementById('email').value;
var tt = validateEmail(email);
if (tt == true) {
xmlhttp.open('POST', 'payment.php', true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send(myProps.join("&"));
} else {
emailWarning();
}
}
function insert() {
try {
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
var myProps = [];
function addProp(id) {
var value = encodeURIComponent(document.getElementById(id).value);
myProps.push(id + "=" + value);
}
addProp('child_name');
addProp('age');
addProp('hometown');
addProp('boy_girl');
addProp('first_name');
addProp('last_name');
addProp('email');
addProp('address1');
addProp('address2');
addProp('city');
addProp('state');
addProp('zip');
addProp('country');
var flagInvalid = false;
var tempArray = document.getElementsByClassName("required");
for (var i = 0; i < tempArray.length; i++) {
if (tempArray[i].value == "") {
flagInvalid = true;
break;
}
}
if (flagInvalid == false) {
postData();
} else {
var log = document.getElementById("log");
log.className = 'show';
var log1 = document.getElementById("log1");
log1.className = 'show';
var log2 = document.getElementById("log2");
log2.className = 'show';
var log3 = document.getElementById("log3");
log3.className = 'show';
var log4 = document.getElementById("log4");
log4.className = 'show';
var log5 = document.getElementById("log5");
log5.className = 'show';
var log6 = document.getElementById("log6");
log6.className = 'show';
var log7 = document.getElementById("log7");
log7.className = 'show';
var log8 = document.getElementById("log8");
log8.className = 'show';
var log9 = document.getElementById("log9");
log9.className = 'show';
var log0 = document.getElementById("log0");
log0.className = 'show';
var logA = document.getElementById("logA");
logA.className = 'show';
}
} catch (e) {
alert('An error occured in inert: ' + e);
}
}
The problem is easily catched when addProp body is changed to this:
function addProp(id) {
var el = document.getElementById(id);
if (el) {
myProps.push(id + "=" + encodeURIComponent(el.value));
}
else {
alert('Not found: ' + id);
}
}
Both boy_girl and email IDs are not present in this HTML:
Boy: <input type="radio" name="boy_girl" id="boy_girl_b" value="boy"/>
Girl:<input type="radio" name="boy_girl" id="boy_girl_g" value="girl"/></li>
...
<input type="text" name="email" id="check" maxlength="64" class="required" />
You can fix it with something like this:
function addProp(name) {
var els = document.getElementsByName(name);
if (els.length) {
myProps.push(name + "=" + encodeURIComponent(els[0].value));
}
else {
alert('Not found: ' + name);
}
}
But in fact, it's only the beginning of the story. myProps are local to insert function yet referenced in postData function; you show validation error signs for all the fields no matter what fields were actually filled... Besides, your code is a bit WET - for example, all these
var log = document.getElementById("log");
log.className = 'show';
var log1 = document.getElementById("log1");
log.className = 'show';
...
... can be easily transformed into this:
var showValidationError = function(id) {
var el = document.getElementById(id);
if (el) {
el.className = 'show';
}
else {
alert('Missing element #' + id);
}
}
...
showValidationError('log');
for (var i = 1; i < 10; i++) {
showValidationError('log' + i);
}
I do understand that you're quite fresh with JS; but it's not about freshness, it's about organizing your code.
I am betting one of the addProp lines is not correct.
Debug this, see what is the last id before the error is thrown.
function addProp(id) {
console.log(id);
var value = encodeURIComponent(document.getElementById(id).value);
myProps.push(id + "=" + value);
}
And when you do that, you will find out that the line
addProp('boy_girl');
will fail since there is no id
<span id="log4" class="hidden" style="color:red"><b>*</b></span>
Boy: <input type="radio" name="boy_girl" id="boy_girl_b" value="boy"/>
Girl:<input type="radio" name="boy_girl" id="boy_girl_g" value="girl"/></li>
So let us change the function to check for id, and than check for the name if the id does not exist.
function addProp(id) {
var input = document.getElementById(id);
if (!input) {
input = document.forms[0][id];
}
var value = encodeURIComponent(input.value);
myProps.push(id + "=" + value);
}
Change it so myProps is outside of the function.
var myProps = []; //<--- Added this line
function insert() {
try {
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
myProps = []; //<---- Changed this line
function addProp(id) {
var input = document.getElementById(id);
if(!input) {
input = document.forms[0][id];
}
console.log(input);
var value = encodeURIComponent(input.value);
myProps.push(id + "=" + value);
}
addProp('child_name');
if you get such error:
always check all your document.getElementById if they don't return null
var node = document.getElementById('someid');
if(node){
do something;
}
but mark that
var node = document.getElementById('someid').value;
or
var node = document.getElementById('someid');
if(node.value){
do something;
}
can still throw the error "can't read property of null", as you don't check if node really exists
Make sure that you're designed IDs are existing on the page!
For example boy_girl does not exist! Only boy_girl_band boy_girl_g
The same applies for the mail. This one has the id check instead of mail.
Use Opera dragonfly or anything alike for basic troubleshooting

getting the names of elements in JS/jQuery

I have some checkbox inputs like so:
<input type="checkbox" name="1" class="filter"/>
<input type="checkbox" name="2" class="filter"/>
...etc...
I'm trying to write a function where any time a checkbox is selected, it generates a string with all the names concatenated. Here's what I have so far:
$('.filter').click(function(event){
var filters = $('.filter').toArray();
var fstr = "";
for (f in filters)
{
fstr = fstr+","+f.name;
}
alert(fstr);
});
The names keep coming up as 'undefined', though (i.e. the alert returns ,undefined,undefined,undefined,undefined,undefined,undefined). How do I access the names?
Here's how it's meant to be done:
$('.filter').click(function (event)
{
var fstr = '';
$('.filter[name]').each(function ()
{
fstr += ',' + $(this).attr('name');
});
alert(fstr);
});
You can use .map() to get what you're after, like this:
$('.filter').click(function(event){
var names = $('.filter').map(function () {
return $(this).attr("name");
}).get().join(',');
alert(names);
});
Just change $('.filter') to $('.filter:checked') if you want a list containing only the checked ones.
$('.filter').click(function(event){
var filters = $('.filter').toArray();
var fstr = "";
for (f in filters)
{
fstr = fstr+","+filters[f].name;
}
alert(fstr);
});
Why are you doing it that way anyway?
$('.filter').click(function(event){
var str = '';
$('.filter').each(function () {
str += $(this).attr('name') +",";
});
alert(str);
});
(function($filters) {
$filters.click(function(event) {
var filters = $filters.toArray();
var fstr = [];
for (var i = filters.length - 1; i > -1; --i) {
fstr.push(filters[i].name);
}
fstr = fstr.join(",");
alert(fstr);
}
})($('.filter'));
Try $(f).name.
How about $(elem).attr("name")?
I'm thinking the convert to array is your problem, try:
var filters = $('.filter');
for(var nI = 0; nI < filters.length; nI++)
filters.eq(nI).attr('name');

Categories