Converting user input from html table to JSON with jQuery - javascript

I am able to convert a pre populated table with data to JSON object with jQuery. Here is the code:
var header = $('table thead tr th').map(function () {
return $(this).text();
});
var tableObj = $('table tbody tr').map(function (i) {
var row = {};
$(this).find('td').each(function (i) {
var rowName = header[i];
row[rowName] = $(this).text();
});
return row;
}).get();
JSON.stringify(tableObj);
And the html table is like this:
<table>
<thead>
<tr>
<th>Name</th>
<th>E-mail</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>jason</td>
<td>jason#example.com</td>
<td>Developer</td>
</tr>
<tr>
<td>ted</td>
<td>ted#example.com</td>
<td>Bear</td>
</tr>
</tbody>
</table>
Now my task is to actually handle empty table with user inputs. When user load the page, the table is empty with no value, after the user entered the input and click submit, I want to convert the user input data into JSON object and pass it back to back-end.
I am trying to make it happen by warp the table into a form, and add <input> tag in each <td>, something like this:
<form>
<table>
<tbody>
<tr>
<td><input type="text"/></td>
<td><input type="text"/></td>
<td><input type="text"/></td>
</tr>
<tr>
<td><input type="text"/></td>
<td><input type="text"/></td>
<td><input type="text"/></td>
</tr>
</tbody>
</table>
<button type="submit">Submit</button>
</form>
I try to use the .submit() method from jQuery to make it work but I am getting syntax errors:
$('form').submit(
var header = $('table thead tr th').map(function () {
return $(this).text();
});
var tableObj = $('table tbody tr').map(function (i) {
var row = {};
$(this).find('td').each(function (i) {
var rowName = header[i];
row[rowName] = $(this).text();
});
return row;
}).get();
JSON.stringify(tableObj);
);
How should I change my code to make it work?

That's happening bacause there is no text in the td. You need to find the value of the input.
1) You need to get the input in the td
2) You need to get the value of the input
Also try to look at the editable div
Try this:
row[rowName] = $(this).find('input').val();

Related

Create Javascript object from HMTL table

I have a table like
<table id="misc_inputs">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
...
I would like to convert that table to a Javascript object like
misc_inputs = {"a": 1, "b": 2, ...
How can the result be generated?
You can use below re-usable javascript method to convert any HTML table into Javascript object.
<table id="MyTable">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
</tbody>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
function ConvertHTMLToJSObject(htmlTableId)
{
var objArr = {};
var trList = $('#' + htmlTableId).find('tr');
$('#' + htmlTableId).find('tbody tr').each(function ()
{
var row = $(this);
var key = $(row).first().text().trim();
var value = $(row).find('input').attr("value");
objArr[key] = value;
});
return objArr;
}
var obj = ConvertHTMLToJSObject("MyTable");
console.log(obj);
});
You can loop through each inputs and create the object:
var misc_inputs = {};
$("#misc_inputs input[type=number]").each(function(i, el){
var k = $(this).closest('td').prev().text();
return misc_inputs[k] = +el.value;
});
console.log(misc_inputs);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="misc_inputs">
<thead>
<tr><th>Property</th><th>Input</th></tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td><input type="number" value="1"></td>
</tr>
<tr>
<td>b</td>
<td><input type="number" value="2"></td>
</tr>
</tbody>
</table>
Probably you can do it without any library but with jQuery it's easier. Something like that should work (not tested):
// Here we will store the results
var result = {};
// Ask jQuery to find each row (TR tag) and call a function for each
$('tr').each(function(){
// Inside a jQuery each() "this" is the current element, the TR tag in this example
var row = $(this);
// We ask jQuery to find every TD inside the current row (the second parameter of a jQuery selector is the parent node for your search). We take the first one and then we take the content of the tag
var label = $("td", row).first().text();
// We ask for an "input" tag inside the current row and we read its "value" attribute
var value = $("input", row).attr("value");
// Store everything in result
result[label] = value;
});

Select all 2nd cell values in a table to array using jQuery

I am working on a requirement, where I need to push numbers in text boxes to an array. The text boxes are in the 2nd cell in the table row and 3rd cell is a date picker.
The code snippet below is giving me all text field values along with date values in array. I need only the values of the text fields to that array. Please help me with solution.
var NumbersArray = $('#myTable input[type=text]').map(function() {
return this.value;
}).get();
console.log(NumbersArray);
This piece of code below is also not working:
var secondCellContents = [],
$('#myTable tbody tr').each(function() {
var $secondCell = $(this).children('td').eq(1).text(),
secondCellContent = $secondCell.text();
secondCellContents.push(secondCellContent);
});
console.log(secondCellContents);
You can do the same thing for 2nd cell also like:
var secondCellContents = $('#myTable tbody tr').map(function() {
return $('td:eq(1)', this).val();
}).get();
console.log(secondCellContents);
Also, the .val() method is primarily used to get the values of form elements such as input, select and textarea and .text() is used to get the combined text contents of each element. The .text() method returns the value of text and CDATA nodes as well as element nodes.
This is how to make it work with your own code.
$(document).ready(function(){
var NumbersArray = $('#myTable td:nth-child(2) input[type="text"]').map(function() {
return $(this).val();
}).get();
console.log(NumbersArray);
//OR
var secondCellContents = [];
$('#myTable tbody tr').each(function () {
var $secondCell = $(this).children('td:eq(1)');
secondCellContent = $secondCell.find('input').val();
secondCellContents.push(secondCellContent);
});
console.log(secondCellContents);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id='myTable'>
<tbody>
<tr>
<td>Row 1</td>
<td><input type='text' value="1" /></td>
<td></td>
</tr>
<tr>
<td>Row 2</td>
<td><input type='text' value="2" /></td>
<td></td>
</tr>
<tr>
<td>Row 3</td>
<td><input type='text' value="3" /></td>
<td></td>
</tr>
</tbody>
</table>

Get clicked column index from row click

I have a row click event. Recently had to add a checkbox to each row. How can I identify the clicked cell on row click event?
Or prevent row click when clicked on the checkbox.
Attempts: this.parentNode.cellIndex is undefined on the row click event.
function pop(row){
alert(row.cells[1].innerText);
}
<table style="width:100%">
<tr>
<th>Select</th>
<th>Site</th>
</tr>
<tr onclick="pop(this);">
<td><input type="checkbox" id="123456" /></td>
<td>Lonodn</td>
</tr>
</table>
Do you want something like this? You can just check the type attribute of the source element of the event and validate whether to allow it or not, you can stop the event using e.stopPropagation();return;.
function pop(e, row) {
console.log(e.srcElement.type);
if(e.srcElement.type === 'checkbox'){
e.stopPropagation();
return;
}else{
console.log(row);
alert(row.cells[1].innerText);
}
}
<table style="width:100%">
<tr>
<th>Select</th>
<th>Site</th>
</tr>
<tr onclick="pop(event, this);">
<td><input type="checkbox" id="123456" /></td>
<td>Lonodn</td>
</tr>
</table>
You should pass in the event details to your function and check the target property:
function pop(e){
// If the target is not a checkbox...
if(!e.target.matches("input[type='checkbox']")) {
alert(e.target.cellIndex);
}
}
<table style="width:100%">
<tr>
<th>Select</th>
<th>Site</th>
</tr>
<tr onclick="pop(event)">
<td><input type="checkbox" id="123456" /></td>
<td>Lonodn</td>
</tr>
</table>
Note: If you have nested elements inside the <td>, you might want to check e.target.closest("td") instead.
Note 2: You might need a polyfill for the matches method depending on which browsers you're supporting.
Here is an example if you don't want to attach a listener on every row :
document.getElementById("majorCities").addEventListener("click", function(e){
if(e.target.type === 'checkbox'){
var checked = e.target.checked;
var tr = e.target.parentElement.parentElement;
var city = tr.cells[1].innerHTML;
console.log(city+":checked="+checked);
}
});
<table id="majorCities" style="width:100%">
<tr>
<th>Select</th>
<th>Site</th>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td>London</td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td>Paris</td>
</tr>
<tr>
<td><input type="checkbox"/></td>
<td>New-York</td>
</tr>
</table>
window.pop = function(row){
console.log('here');
var parent = row.parentNode;
Array.from(row.parentNode.querySelectorAll('tr')).forEach(function(tr, index){
if (tr === row) {
alert(index)
}
})
}
https://jsfiddle.net/sz42oyvm/
Here is for the pleasure, another example with an object containing the cities' names and a method to draw the table with ids corresponding to the name of the clicked city, so getting the clicked name is easier.
(function () {
var mySpace = window || {};
mySpace.cities = {};
mySpace.cities.pointer = document.getElementById("majorCities");
mySpace.cities.names = ["Select","City"];
mySpace.cities.data = [{"name":"Paris"},{"name":"New Delhi"},{"name":"Washington"},{"name":"Bangkok"},{"name":"Sydney"}];
mySpace.cities.draw = function(){
this.pointer.innerHTML="";
var html = "";
html+="<tr>"
for(var i=0;i < this.names.length;i++){
html+="<th>"+this.names[i];
html+="</th>"
}
html+="</tr>"
for(var i=0;i < this.data.length;i++){
html+="<tr>"
html+="<td><input id='"+this.data[i].name+"' type='checkbox'/></td>"
html+="<td>"+this.data[i].name+"</td>"
html+="</tr>"
}
this.pointer.innerHTML=html;
}
mySpace.cities.draw();
mySpace.cities.pointer.addEventListener("click", function(e){
if(e.target.type === 'checkbox'){
var checked = e.target.checked;
var city = e.target.id;
console.log(city+":checked="+checked);
}
});
})();
table {width:25%;background:#ccc;border:1px solid black;text-align:left;}
td,tr {background:white;}
th:first-of-type{width:20%;}
<table id="majorCities">
</table>

Javascript add Row, one function for different tables

I have a few tables like this
<table id="table_1">
<tr>
<td><input type="text" name="date[]"</td>
</tr>
</table>
the number of the <td>'s is very variable.
Currently I'm using a function like this:
function addRow(){
var table = document.getElementById('table_1');
var row = table.insertRow(-1);
var cell1 = row.insertCell(0)
....
cell1.innerHTML="<input type='text' name='date[]' />
}
using this method, it would require a custom function for every type of table.
Is there a way, to add a Line to a table, which is exactly the same as the last row?
In a table with 7 cells, 7 cells would be added, with the right content.
Is this possible in pure JS?
You could do it this way with jQuery:
Edit:
Sorry, I did not see you wanted pure JS.
jQuery
$('button').click(function(){
var table = $(this).prev('table');
var lastrow = $('tr:last-child', table).html();
table.append('<tr>' + lastrow + '</tr>');
});
HTML
<table>
<tr>
<th>Name</th>
<th>Country</th>
<th>Age</th>
</tr>
<tr>
<td><input type="text"/></td>
<td><input type="text"/></td>
<td><input type="text"/></td>
</tr>
</table>
<button>Add a row</button>
<table>
<tr>
<th>Meal</th>
<th>Price</th>
</tr>
<tr>
<td><input type="text"/></td>
<td><input type="text"/></td>
</tr>
</table>
<button>Add a row</button>
JS Fiddle Demo
Maybe this is what you need : http://jsfiddle.net/thecbuilder/bx326s31/1/
<input type="button" onclick="cloneRow()" value="Clone Row" />
<input type="button" onclick="createRow()" value="Create Row" />
<table>
<tbody id="tableToModify">
<tr id="rowToClone">
<td><input type="text" name="txt[]"/></td>
<td>bar</td>
</tr>
</tbody>
</table>
function cloneRow() {
var row = document.getElementById("rowToClone"); // find row to copy
var table = document.getElementById("tableToModify"); // find table to append to
var clone = row.cloneNode(true); // copy children too
clone.id = "newID"; // change id or other attributes/contents
table.appendChild(clone); // add new row to end of table
}
function createRow() {
var row = document.createElement('tr'); // create row node
var col = document.createElement('td'); // create column node
var col2 = document.createElement('td'); // create second column node
row.appendChild(col); // append first column to row
row.appendChild(col2); // append second column to row
col.innerHTML = "qwe"; // put data in first column
col2.innerHTML = "rty"; // put data in second column
var table = document.getElementById("tableToModify"); // find table to append to
table.appendChild(row); // append row to table
}
Refer : https://stackoverflow.com/a/1728578/3603806

How to keep adding data to next table column

This Fiddle Example shows a comparison table that dynamically shows information in a column when a button is clicked. Once the table is filled up, I want to start the whole process again. But as the example shows, the buttons are stuck at adding information to th:nth-child(2) and td:nth-child(2) during the second time instead of moving on to the next column like during the first time.
I'm guessing this part needs some change if( allCells === fullCells ) { to keep information being added to next columns.
HTML
<div class="area">
<button>Gah</button>
</div>
<div class="area">
<button>Kaj</button>
</div>
<div class="area">
<button>Fdw</button>
</div>
<div class="area">
<button>ffdf</button>
</div>
<table>
<thead>
<tr>
<th>Placeholder</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Age</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Name</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Race</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Nationality</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Education</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Language</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Code:
$(function() {
$('.area').each(function(){
var area = $(this),
filltable ='',
button = $(this).find('button'),
buttontext = button.text();
button.on("click",function(){
var allCells = $('table').find('th,td').length;
var fullCells = $('table').find('th,td').filter(function() {
return $(this).text() != '';
}).length;
if( allCells === fullCells ) { // If table is full
$('table').find('th,td').not(':first-child').removeClass('addinfo');
filltable();
}
else { // If table isn't full
filltable = function(){
var i = $('th.addinfo').length !== 0 ? $('th.addinfo:last').index() : 0;
console.log( i );
i + 2 > $('th').length ||
$('th,td').filter(':nth-child(' + (i + 2) + ')')
.addClass( 'addinfo' ).html(buttontext);
}
filltable();
}
}); // end button on click function
});
});
Please see the attached link for demo. I have created a function name cleartable() which clears the table if its full and have used your old filltable() function to repopulate. There is repetition of code which you will have to clean up.
th:nth-child(2) identifies second child of th.
td:nth-child(2) identifies second column.
Similarly if you wanted to do something with let say second row, you can use tr:nth-child(2).
I hope this helps you understand a little about parent-child relationship in jquery.
JSFIDDLE DEMO
function clearTable() {
$('table th:nth-child(2)').html('');
$('table th:nth-child(3)').html('');
$('table th:nth-child(4)').html('');
$('table td:nth-child(2)').html('');
$('table td:nth-child(3)').html('');
$('table td:nth-child(4)').html('');
}
http://jsfiddle.net/jqVxu/1/
I think you'd better to count th only. count all td and th make me confused.
$(function () {
function filltable(buttontext) {
var i = $('th.addinfo').length !== 0 ? $('th.addinfo:last').index() : 0;
i + 2 > $('th').length || $('th,td').filter(':nth-child(' + (i + 2) + ')')
.addClass('addinfo').html(buttontext);
}
$('.area').each(function () {
var area = $(this),
button = $(this).find('button'),
buttontext = button.text();
button.on("click", function () {
var allCells = $('table').find('th').length-1;
var fullCells = $('table th.addinfo').length;
console.log(allCells, fullCells);
if (allCells === fullCells) { // If table is full
$('table .addinfo').removeClass('addinfo');
filltable(buttontext);
} else { // If table isn't full
filltable(buttontext);
}
});
});
});

Categories

Resources