Defining JSON dynamically - can't find what I am doing wrong - javascript

I am trying to put form content in a JSON dynamically.
It worked before, but after I added a extra layer (arrays in arrays) there seem to be something that I am doing wrong:
aJSON = {};
aJSON['properties'] = [];
aJSON['options'] = [];
aJSON['arrays'] = [];
$('input').each(function () {
if($(this).attr('name') != undefined) {
if($(this).attr('name').indexOf('[]') > -1) {
if(aJSON['arrays'][$(this).attr('name')] == undefined) {
aJSON['arrays'][$(this).attr('name')] = [];
}
if($(this).is(':checked')) {
aJSON['arrays'][$(this).attr('name')][$(this).attr('value')] = 1;
} else {
aJSON['arrays'][$(this).attr('name')][$(this).attr('value')] = 0;
}
} else {
aJSON['properties'][$(this).attr('name')] = $(this).val();
}
}
});
$('select').each(function () {
if($(this).attr('name') != undefined) {
aJSON['properties'][$(this).attr('name')] = $(this).val();
}
});
var array = getUrlVars();
aJSON['options']['type'] = array['type'];
aJSON['options']['id'] = array['id'];
aJSON['options']['view'] = pageSpecificVariables['view'];
The top 4 lines are just a tryout, I also tried:
aJSON = {'properties':[], 'options':[], 'arrays':[]}
But the only result I am getting is an object with empty arrays of properties, options and arrays.
Before I put all the values directly in aJSON and that worked perfectly.
But for categorizing, I need the 3 categories to exist.
Any idea why my values aren't written to the aJSON?
EDIT
Added JSfiddle here: http://jsfiddle.net/abayob/pob32fs1/

I assume you are trying to serialise a form.
Use jQuery's serializeArray function instead
var myform = $("#myform");
var data = JSON.stringify( myform.serializeArray() );
Update
Because you're trying to use arrays like object-maps
Solution: http://jsfiddle.net/pob32fs1/8/
var oJSON = {
properties: {},
options: {},
arrays: {}
};
$('input[name]').each(function(){
var $el = $(this),
value = $el.attr("value"),
name = $el.attr('name');
if(name.indexOf('[]') >= 0)
{
oJSON.arrays[name] = oJSON.arrays[name] || {};
oJSON.arrays[name][value] = $el.is(':checked') ? 1 : 0;
} else {
oJSON.properties[name] = $el.val();
}
});
$('select[name]').each(function(){
var $el = $(this);
oJSON.properties[$el.attr('name')] = $el.val();
});
oJSON.options['type'] = 'user';
oJSON.options['id'] = 1;
oJSON.options['view'] = 'user-settings';
console.log(oJSON);

Assuming that the name and value attributes of your various inputs are strings, and not just numbers, you should be using nested objects, not nested arrays. You're trying to use associative arrays, which are not available in JavaScript.
var oJSON = {};
$('._save, .btn-success').click(function() {
oJSON = {
properties: {},
options: {},
arrays: {}
};
$('input').each(function() {
if ($(this).attr('name') != undefined) {
if ($(this).attr('name').indexOf('[]') > -1) {
if (oJSON['arrays'][$(this).attr('name')] == undefined) {
oJSON['arrays'][$(this).attr('name')] = {};
}
if ($(this).is(':checked')) {
oJSON['arrays'][$(this).attr('name')][$(this).attr('value')] = 1;
} else {
oJSON['arrays'][$(this).attr('name')][$(this).attr('value')] = 0;
}
} else {
oJSON['properties'][$(this).attr('name')] = $(this).val();
}
}
});
$('select').each(function() {
if ($(this).attr('name') != undefined) {
oJSON['properties'][$(this).attr('name')] = $(this).val();
}
});
oJSON['options']['type'] = 'user';
oJSON['options']['id'] = 1;
oJSON['options']['view'] = 'user-settings';
console.log(oJSON);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="tab-content">
<div id="tab-general" class="tab-pane active">
<h4>Gebruikersnaam</h4>
<input type="text" value="John Doe" name="username" class="form-control" required="" placeholder="J. Average">
<h4>E-mailadres</h4>
<input type="email" value="info#info.info" name="mailaddress" class="form-control" required="" placeholder="E-mail#adres.nl">
<div class="row">
<div class="col-md-6">
<input type="password" name="password" minlength="10" class="form-control" placeholder="Nieuw wachtwoord">
</div>
<div class="col-md-6">
<input type="password" name="password_retype" minlength="10" class="form-control" placeholder="Herhaal wachtwoord">
</div>
</div>
<input type="password" name="password_old" class="form-control margin-y-10" placeholder="Huidig Wachtwoord">
</div>
<div id="tab-sites" class="tab-pane">
<h4>Websites</h4>
<div id="site_container">
<div class="checkbox block">
<input name="sites[]" checked="" type="checkbox" value="0">
<label>A</label>
</div>
<div class="checkbox block">
<input name="sites[]" checked="" type="checkbox" value="1">
<label>B</label>
</div>
<div class="checkbox block">
<input name="sites[]" checked="" type="checkbox" value="2">
<label>C</label>
</div>
</div>
</div>
</div>
<div class="panel-footer">
<button type="button" class="btn btn-warning _cancel">Annuleren</button>
<button type="button" class="btn btn-success _save">Opslaan</button>
</div>

Related

Issue with multi dimensional becoming empty after assigning to var

I'm having a very strange issue with javascript where I'm building a multi dimensional array and somehow it's being emptied to [[]] on var assignment.
The target being passed to the buildFormObject function is a html form element.
if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
var el = this;
if (!document.documentElement.contains(el)) return null;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
var submit = document.getElementsByClassName('submit');
submitForm_click(submit);
function submitForm_click (trigger) {
if (trigger.length > 0) {
for (var t of trigger) {
t.addEventListener('click', function (e) {
e.preventDefault();
submitForm(t.parentNode);
});
}
} else {
trigger.addEventListener('click', function (e) {
e.preventDefault();
submitForm(trigger.parentNode);
});
}
}
function submitForm (target) {
var info = buildFormObject(target);
console.log(buildFormObject(target));
console.log(info);
}
function buildFormObject (target) {
var inputs = target.querySelectorAll('input,select');
var results = [];
var multi = [];
var iter = 0;
var pos = 0;
for (var input of inputs) {
if (iter > 0) {
iter = iter - 1;
continue;
}
if (input.parentNode.closest('.multiInput') != null) {
var obj = [];
var parent = input.parentNode.closest('.multiInput');
var children = parent.querySelectorAll('input,select');
for (var i of children) {
if (checkIfValueExist(i, i.type)) {
obj[i.name] = i.value;
}
}
multi[pos] = obj;
results[parent.attributes.name.nodeValue] = multi;
pos = pos + 1;
iter = children.length-1;
} else if (checkIfValueExist(input, input.type)) {
results[input.name] = input.value;
pos = 0;
multi = [];
}
}
return results;
}
function checkIfValueExist (target, type) {
switch (type) {
case 'text':
return (target.value == "" ? false : true);
break;
case 'select-one':
return (target.value == "" ? false : true);
break;
case 'checkbox':
return (target.checked === false ? false : true);
break;
case 'radio':
return (target.checked === false ? false : true);
break;
case 'button':
return false;
break;
case 'submit':
return false;
break;
default:
return true;
break;
}
}
<form id="ct">
<input type="hidden" name="task" value="createTable"/>
<div id="tableSection" class="flexContainer">
<div class="block">
<label for="dbName">Select Database</label>
<select name="dbName" class="dbList" required>
<option value="" disabled selected>Please Select</option>
<option value="1">test</option>
</select>
</div>
<div class="block">
<label for="tableName">Table Name</label>
<input type="text" name="tableName" required/>
</div>
</div>
<div class="row flexContainer multiInput" name="tableRow">
<div class="trColumn">
<label for="columnName">Name</label>
<input type="text" name="columnName" required/>
</div>
<div class="trColumn">
<label for="columnType">DataType</label>
<select name="columnType" required>
<option value="" disabled selected>Please Select</option>
<option value="1">CHAR</option>
</select>
</div>
<div class="trColumn">
<label for="columnLength">Length</label>
<input type="text" name="columnLength"/>
</div>
<div class="trColumn">
<label for="columnPK">PK</label>
<input type="checkbox" name="columnPK" value="1"/>
</div>
<div class="trColumn">
<label for="columnDefault">DefaultValue</label>
<input type="text" name="columnDefault"/>
</div>
</div>
<input type="button" class="submit" value="Submit" />
</form>
Result 1:
[task: "createDBTable", dbName: "1", tableName: "tester", tableRow: Array(1)]
dbName: "1"
tableName: "tester"
tableRow: [Array(0)]
task: "createDBTable"
length: 0
__proto__: Array(0)
Result 2:
[task: "createDBTable", dbName: "1", tableName: "tester", tableRow: Array(1)]
dbName: "1"
tableName: "tester"
tableRow: "[[]]"
task: "createDBTable"
length: 0
__proto__: Array(0)
What I don't understand is why the tableRow is going from an Array(6) value to [[]] just because I setting the original variable, the returned value from the buildFormObject function, to a variable.
ADDITIONAL INFORMATION
In the code snippet above I have included the code I'm working with. There seems to be a small quirk where the console.log is only showing [], but you you type one of the property names that should be there like, "tableName"then you can access the value. This isn't true for the problem property of "tableRow" since the nested array is showing as []. I'm not sure if it's the testing software, but if you try it on a local test environment then you shouldn't have any issues seeing what my initial problem is.

Loop through inputs and add them

Trying to loop through all the inputs, when more are added, and add them all to the total (var = paidTotal). I'm getting NaN for the total and Cannot read property 'length' of undefined. Pretty sure the issue is in the peoplepaid() function.
In the peoplePaid() onclick function I'm trying to loop through all the fieldInputs (class="person") depending on how many inputs are created and add the total to #paidTotal. Hopefully that's helpful.
$(document).ready(function() {
var maxFields = 20;
var addButton = $('#plusOne');
var deleteButton = $('#minusOne');
var wrapper = $('#userNumbers');
var fieldInput = '<div><input type="text" name="persons" class="persons"/></div>';
var x = 1;
$(addButton).click(function() {
if (x < maxFields) {
x++;
$(wrapper).append(fieldInput);
}
});
$(deleteButton).click(function(e) {
e.preventDefault();
var myNode = document.getElementById("userNumbers");
i = myNode.childNodes.length - 1;
if (i >= 0) {
myNode.removeChild(myNode.childNodes[i]);
x--;
}
});
});
function peoplePaid() {
var checkTotal = document.getElementById('check').value;
var personsCheck = document.getElementsByClassName('persons').value;
var inputs = document.getElementsByClassName('persons');
var paidTotal = document.getElementById('paidTotal');
for (var i = 1; i < personsCheck.length; i += 1) {
paidTotal[i] += personsCheck;
}
paidTotal.innerHTML = checkTotal - personsCheck;
}
<h3>Check Total</h3>
$ <input type="text" id="check" value="" />
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<button type="button" onclick="plusOne()" id="plusOne">+</button>
<button type="button" onclick="minusOne()" id="minusOne">-</button>
<div>
<div id="userNumbers">
<input type="text" class="persons" name="person">
</div>
</div>
<button onclick="peoplePaid()">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The reason you are getting Cannot read property 'length' of undefined is because
var personsCheck = document.getElementsByClassName('persons').value;
will return undefined.
document.getElementsByClassName('persons')
will return an array of DOM elements and arrays do not have a value property. Then when you access
personsCheck.length
in the loop you get Cannot read property 'length' of undefined because personsCheck is undefined.
I refactored a bit but I used map to get an array of the values then summed them up using reduce
run the snippet below
$(document).ready(function() {
const maxFields = 20;
const wrapper = $('#userNumbers');
const fieldInput = '<div><input type="text" name="persons" class="persons"/></div>';
const reducer = (a,c) => parseInt(a,10) + parseInt(c,10);
$('#plusOne').click(() =>
$("#userNumbers .persons").length < maxFields &&
$(wrapper).append(fieldInput));
$('#deleteButton').click(()=> $("#userNumbers .persons").last().remove());
$('#peoplePaid').click( () => {
const arr= $("#userNumbers .persons").map(function(){
return $(this).val();
}).get();
$('#paidTotal').html(arr.reduce(reducer));
})
});
<h3>Check Total</h3>
$ <input type="text" id="check" value="" />
<h3>Number of People: <span id="numberOfPeople"></span></h3>
<button type="button" id="plusOne">+</button>
<button type="button" id="minusOne">-</button>
<div>
<div id="userNumbers">
<input type="number" class="persons" name="person">
</div>
</div>
<button id="peoplePaid">Calculate</button>
<!--Paid Amount-->
<div>
<h3>Paid Amount: <span id="paidTotal"></span></h3>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to add if input is empty within this code?

I'm a bit stuck on how to add in this code if the inputs are empty, to shoot an alert. Would I add another function within the first? Any hints would be appreciated!
function getCandidateNames() {
var inputs = document.getElementsByTagName("input");
var result = [];
for (var i = 0; i < inputs.length; i += 1) {
if (inputs[i].getElementsByTagName("candidate")) {
result.push(inputs[i].value);
}
}
return result;
}
function putCandidateNames(names) {
document.getElementById("candidateName1").innerHTML = names[0];
document.getElementById("candidateName2").innerHTML = names[1];
document.getElementById("candidateName3").innerHTML = names[2];
}
function candidateNames() {
putCandidateNames(getCandidateNames());
}
The HTML
<fieldset id="candidates">
<legend>Candidates</legend>
<div>
<label for="cand1">Candidate 1</label>
<input class="candidate" id="cand1" placeholder="Candidate">
</div>
<div>
<label for="cand2">Candidate 2</label>
<input class="candidate" id="candName" placeholder="Candidate">
</div>
<div>
<label for="cand3">Candidate 3</label>
<input class="candidate" id="candName" placeholder="Candidate">
</div>
</fieldset>
You have many problems in your code that needs to be fixed:
You can't use the same id id="candName" for multiple elements in the page.
This code inputs[i].getElementsByTagName("candidate") is completely wrong here you should use getElementsByClassName("candidate") instead, because you don't have candidate tags you used them as classes.
And instead of getting the inputs nodeList then iterate over it with inputs[i].getElementsByTagName("candidate") you can just use document.getElementsByClassName("candidate").
This is how should be your code:
function getCandidateNames() {
var inputs = document.getElementsByClassName("candidate");
var result = [];
if (Array.prototype.some.call(inputs, function(input) {
return input.value === "";
})) {
alert("Inputs should not be empty!!!");
return false;
}
Array.prototype.forEach.call(inputs, function(input) {
result.push(input.value);
});
return result;
}
Demo:
function getCandidateNames() {
var inputs = document.getElementsByClassName("candidate");
var result = [];
if (Array.prototype.some.call(inputs, function(input) {
return input.value === "";
})) {
alert("Inputs should not be empty!!!");
return false;
}
Array.prototype.forEach.call(inputs, function(input) {
result.push(input.value);
});
console.log(result);
return result;
}
<fieldset id="candidates">
<legend>Candidates</legend>
<div>
<label for="cand1">Candidate 1</label>
<input class="candidate" id="cand1" placeholder="Candidate">
</div>
<div>
<label for="cand2">Candidate 2</label>
<input class="candidate" id="candName" placeholder="Candidate">
</div>
<div>
<label for="cand3">Candidate 3</label>
<input class="candidate" id="candName2" placeholder="Candidate">
</div>
</fieldset>
<button onclick="getCandidateNames()">Validate</button>
Note:
Note the use of Array.prototype.forEach.call and Array.prototype.some.call, which are used to loop over the nodeList borrowing JavaScript Array built-in functions.
Alternative:
This is an alternative using simple syntax:
function getCandidateNames() {
var inputs = document.getElementsByClassName("candidate");
var result = [];
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].value !== "") {
result.push(inputs[i].value);
} else {
alert("Inputs can't be empty !!!");
return false;
}
}
return result;
}
Demo:
function getCandidateNames() {
var inputs = document.getElementsByClassName("candidate");
var result = [];
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].value !== "") {
result.push(inputs[i].value);
} else {
alert("Inputs can't be empty !!!");
return false;
}
}
console.log(result);
return result;
}
<fieldset id="candidates">
<legend>Candidates</legend>
<div>
<label for="cand1">Candidate 1</label>
<input class="candidate" id="cand1" placeholder="Candidate">
</div>
<div>
<label for="cand2">Candidate 2</label>
<input class="candidate" id="candName" placeholder="Candidate">
</div>
<div>
<label for="cand3">Candidate 3</label>
<input class="candidate" id="candName2" placeholder="Candidate">
</div>
</fieldset>
<button onclick="getCandidateNames()">Validate</button>

get data from input to array

<h2>Add Another Input Box</h2>
<div id="p_scents">
<p>
<label for="p_scnts"><input type="text" id="p_scnt" size="20" name="p_scnt" value="" placeholder="Input Value" /> <input type="checkbox" id="c_scnt" name="c_scnt" class="show"> <input type="text" id="more" name="more" class="hide"> </label>
</p>
</div>
<span id="getall">Get all</span>
ALL CODE: http://jsfiddle.net/tZPg4/1420/
Is possible click on Get all and get all data from all inputs and next use them with loop each and get data: this.one (first input(text)), this.two (second input(checkbox)), this.three (third input - hidden )? for example:
$("#getall").click(function(){
//here get all data to array, but how?
array.each(function(i){
var html = $("<tr><td>this.one</td><td>this.two</td><td>this.three</td></tr>").appendTo("#myTable");
});
})
LIVE: http://jsfiddle.net/tZPg4/1420/
Something like this should work?
$("#getall").click(function(){
var myRow = document.createElement("tr");
var array = new Array()
$.each($("#p_scents").find("p"), function(ind, elem) {
var inputCol = new Array();
console.log("Adding row");
$.each($(elem).find("input"), function(ind2, inputElem) {
if ($(inputElem).attr("type") != "checkbox") {
inputCol [inputCol .length] = $(inputElem).val();
}
else {
inputCol [inputCol .length] = $(inputElem).is(":checked");
}
});
array[array.length] = inputCol;
});
console.log("Outputting results");
for (var i in array) {
console.log("Row: "+i);
for (var j in array[i]) {
console.log("Input: "+j + " == " + array[i][j]);
}
}
});
var arr = new Array();
$( 'input' ).each(function(index)
{
arr[arr.length] = $(this).val();
})

Jquery filtering through a multiple range of numbers

Think I'm getting stuck... I'm attempting to take a list of items and create filters based on attributes to the object. I stripped it down into an easier example of books with a cost and year. I currently have a list of books on the page and filters (checkboxes) that can be selected to only show books within a range of cost and/or year. Here is the code I have so far:
<div id="filters">
<h1>FILTERS</h1>
<div class="filter filter_cost">
<input class="target" type="checkbox" min="0" max="9" />Under $10.00<br/>
<input class="target" type="checkbox" min="10" max="19" />$10-$19<br/>
<input class="target" type="checkbox" min="20" max="29" />$20-$29<br/>
<input class="target" type="checkbox" min="30" max="39" />$30-$39<br/>
<input class="target" type="checkbox" min="40" max="1000" />$40 and Over<br/>
</div>
<div class="filter filter_year">
<input class="target" type="checkbox" min="1700" max="1799" />18th Century<br/>
<input class="target" type="checkbox" min="1800" max="1899" />19th Century<br/>
<input class="target" type="checkbox" min="1900" max="1999" />20th Century<br/>
<input class="target" type="checkbox" min="2000" max="2999" />21st Centruy<br/>
</div>
</div>
<div id="books">
<h1>BOOKS</h1>
<div class="book">
<h1>Book 1</h1>
<input type="hidden" name="cost" value="13" />
<input type="hidden" name="year" value="1997" />
</div>
<div class="book">
<h1>Book 2</h1>
<input type="hidden" name="cost" value="22" />
<input type="hidden" name="year" value="1872" />
</div>
</div>
And my jQuery (using 1.6.2):
$(document).ready(function () {
$("input.target").change(function () {
filterResults();
});
});
function filterResults(){
$(".book").each(function () {
var cost = $(this).find("input[name='cost']").val();
var year = $(this).find("input[name='year']").val();
var cover = $(this).find("input[name='cover']").val();
var isHidden = false;
//console.log("Cost in Range: "+filterRange(cost, ".filter_cost"));
//console.log("Year in Range: "+filterRange(year, ".filter_year"));
var filterCost = filterRange(cost, ".filter_cost")?showBook($(this)):hideBook($(this));
var filterYear = filterRange(year, ".filter_year")?showBook($(this)):hideBook($(this));
isHidden?"":filterCost;
isHidden?"":filterYear;
function showBook(obj) {
obj.show();
}
function hideBook(obj) {
isHidden = true;
obj.hide();
}
})
}
function filterRange(amount, elem) {
var checkedInputs = $(elem).find("input:checked").length;
var totalInputs = $(elem).find("input").length;
var inRange = function(){
$(elem).find("input:checked").each(function () {
var min = $(this).attr('min');
var max = $(this).attr('max');
if(amount >= min && amount <= max){
return true;
} else {
return false;
}
});
};
if(checkedInputs == 0 || totalInputs == checkedInputs ){
return true;
}
if(inRange()){
return true;
} else {
return false;
}
}
My issue is that in the filterRange function I'm not sure how to create a range of conditionals based on each input that is checked. So that a price range could be 10-19 and 30-39. My attempt (var inRange) was to go through each checked input, check if the cost was with in the range, then return true, else return false. I think I'm just fundamentally getting off track and unsure if this method would work at all. Any input would be much appreciated.
In the jquery each loop on dom element return statement breaks out of the loop. So your implemenation is wrong. Try this.
function filterRange(amount, elem) {
var checkedInputs = $(elem).find("input:checked").length;
var totalInputs = $(elem).find("input").length;
var returnValue = false;
$(elem).find("input:checked").each(function () {
var min = $(this).attr('min');
var max = $(this).attr('max');
if(amount >= min && amount <= max){
returnValue = true;
return true;
}
});
return (checkedInputs == 0 || totalInputs == checkedInputs || returnValue );
}
Try:
function filterRange(amount, elem) {
var checkedInputs = $(elem).find("input:checked").length;
var totalInputs = $(elem).find("input").length;
var inRange = false;
$(elem).find("input:checked").each(function () {
var min = $(this).attr('min');
var max = $(this).attr('max');
if (amount >= min && amount <= max) {
inRange = true;
return false;
}
});
if (checkedInputs == 0 || totalInputs == checkedInputs) {
return true;
}
if (inRange) {
return true;
} else {
return false;
}
}

Categories

Resources