what is the best way to save a dynamic table data in to json.
I have two tables that i want to save in to one json file.
i"m able to console the regular table data but i"m unable to locate the td value of a dynamic table.
my plan to save to json and clear the forum for additional DC/pop info adding
so please check the save button and help me understand how to continue
1. save the popisp table
2. clear and make it ready for the next pop entry.
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js">
$(document).ready(function(){
$(".add-row").click(function(){
var name = $("#ispname").val();
var capasity = $("#ispcapasity").val();
var markup = "<tr><td><input type='checkbox' name='record'></td><td>" + name + "</td><td>" + capasity + "</td></tr>";
$('#popisp tr:last').after(markup);
});
$(".delete-row").click(function(){
$('#popisp').find('input[name="record"]').each(function(){
if($(this).is(":checked")){
$(this).parents("tr").remove();
}
});
});
$(".save_asJSON").click(function(){
var pop_name = document.getElementById("popname").value
jsonobj.pops[pop_name] = {
name: document.getElementById("popname").value,
city: document.getElementById("popcity").value,
subnet: document.getElementById("popsubnet").value,
}
console.log(jsonobj);
});
});
var jsonobj = {
pops: {}
};
</script>
<body>
<table id="PoP_Details">
<tr>
<td>Pop name:</td>
<th colspan="2"><input id="popname" name='pops[name]'></input></th>
</tr>
<tr>
<td>City:</td>
<th colspan="2"><input id="popcity" name='pops[name][city]'></input></th>
<tr>
<td>POP Subnet</td>
<th colspan="2"><input id="popsubnet" name='pops[name][subnet]'></input></th>
</tr>
</table>
<form>
<input type="text" id="ispname" placeholder="Name">
<input type="text" id="ispcapasity" placeholder="capasity">
<input type="button" class="add-row" value="Add ISP">
</form>
<div class="wrap">
<table id="popisp">
<thead>
<tr>
<th>Select</th>
<th>Name</th>
<th>capasity</th>
</tr>
</thead>
<tbody>
<tr>
</tr>
</tbody>
</table>
</div>
<button type="button" class="delete-row">Delete Row</button>
<button type="button" class="save_asJSON">Save</button>
</body>
here is how I like my json to looks like
{
"pops": {
"pop1": {
"name": "pop1",
"city": "blabla",
"subnet": "192.168.1.0/24",
"isps": [
{
"name": "isp1",
"capasity": "10M"
},
{
"name": "isp2",
"capasity": "10M"
}
]
},
"pop2": {
"name": "pop2",
"city": "blabla",
"subnet": "192.168.2.0/24",
"isps": [
{
"name": "isp3",
"capasity": "20M"
},
{
"name": "isp4",
"capasity": "30M"
},
{
"name": "isp5",
"capasity": 500M"
}
]
}
}
}
I can suggest the following guidance :
Save inputs as jQuery variables for further use, not necessary but usefull, ex :
var $input = $('#popname');
Add a function that use the table, iterate through the <tr> in <tbody> and retrieve the <td> to compose object to save for each row, return it as an array.
Add a function that use the inputs to clear the form
Call the two function above when saving the array, the first to add the data to the json saved, the second to clear the form.
I show bellow an update of your snippet with complete modification, but I suggest you use use the guidance to implement it in a way that suits your needs.
$(document).ready(function(){
// Inputs as jQuery variables
var $nameInput = $("#popname");
var $cityInput = $("#popcity");
var $subnetInput = $("#popsubnet");
var $ispNameInput = $("#ispname");
var $ispCapacityInput = $("#ispcapasity");
var $popispTable = $('#popisp');
// array for convenience loop
var inputs = [$nameInput, $cityInput, $subnetInput,
$ispNameInput, $ispCapacityInput];
// function to clear all inputs and remove isp rows
function clearForm() {
inputs.forEach(e => e.val(''));
$popispTable.find('tbody').find('tr').remove();
$popispTable.find('tbody').append($('<tr>'));
}
// function that return an array of isp rows data
function ispTableData() {
var rows = $popispTable.find('tbody').find('tr');
if (!rows.length) return [];
console.log(rows.length);
var data = rows.toArray().reduce((data, e, k) => {
var tds = $(e).find('td');
if (!tds.length) return [];
data.push({
checked: $(tds[0]).find('input').is(":checked"),
name: $(tds[1]).text(),
capasity: $(tds[2]).text()
});
return data;
}, []);
return data;
}
$(".add-row").click(function(){
var name = $("#ispname").val();
var capasity = $("#ispcapasity").val();
var markup = "<tr><td><input type='checkbox' name='record'></td><td>" + name + "</td><td>" + capasity + "</td></tr>";
$('#popisp tr:last').after(markup);
// eventually clear row form inputs here as well
});
$(".delete-row").click(function(){
$('#popisp').find('input[name="record"]').each(function(){
if($(this).is(":checked")){
$(this).parents("tr").remove();
}
});
});
$(".save_asJSON").click(function(){
var pop_name = document.getElementById("popname").value
jsonobj.pops[pop_name] = {
name: $("#popname").val(),
city: $("#popname").val(),
subnet: $("#popsubnet").val(),
// add the isp rows data
isps: ispTableData()
}
console.log(jsonobj);
// clear the form
clearForm();
});
});
var jsonobj = {
pops: {}
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<table id="PoP_Details">
<tr>
<td>Pop name:</td>
<th colspan="2"><input id="popname" name='pops[name]'></input></th>
</tr>
<tr>
<td>City:</td>
<th colspan="2"><input id="popcity" name='pops[name][city]'></input></th>
<tr>
<td>POP Subnet</td>
<th colspan="2"><input id="popsubnet" name='pops[name][subnet]'></input></th>
</tr>
</table>
<form>
<input type="text" id="ispname" placeholder="Name">
<input type="text" id="ispcapasity" placeholder="capasity">
<input type="button" class="add-row" value="Add ISP">
</form>
<div class="wrap">
<table id="popisp">
<thead>
<tr>
<th>Select</th>
<th>Name</th>
<th>capasity</th>
</tr>
</thead>
<tbody>
<tr>
</tr>
</tbody>
</table>
</div>
<button type="button" class="delete-row">Delete Row</button>
<button type="button" class="save_asJSON">Save</button>
</body>
Related
Why is .append() creating 2 identical rows in this code when I click Add New button? I don't see why 2 appends happen. Am I misunderstanding something? This doesn't happen with vanilla javascript but happens with jquery.
I added the table which includes the tbody tag at the end of the table where I would like to append the template string in function onAddProduct(e).
(Note: I removed html since it was an assignment.)
here is the code snippet
$(function() {
var $formEl = $('form');
var $tbodyEl = $('tbody');
var $tableEl = $('table');
function onAddProduct(e) {
e.preventDefault();
var $pName = $('#pname').val();
var $pCat = $('#pcat').val();
var $pPrice = $('#pprice').val();
$tbodyEl.append(`
<tr>
<td>${$pName}</td>
<td>${$pCat}</td>
<td>${$pPrice}</td>
<td><button class="deleteBtn">Delete</button></td>
</tr>
`);
}
function onDeleteRow(e) {
if (!e.target.classList.contains("deleteBtn")) {
return;
}
const btn = e.target;
btn.closest("tr").remove();
}
//formEl.addEventListener("submit", onAddProduct);
$formEl.on({
submit: onAddProduct
});
//tableEl.addEventListener("click", onDeleteRow);
$tableEl.on({
click: onDeleteRow
});
});
Consider the following.
$(function() {
var $formEl = $('form');
var $tbodyEl = $('tbody');
var $tableEl = $('table');
function onAddProduct(e) {
e.preventDefault();
var row = $("<tr>").appendTo($("tbody", $tableEl));
$("<td>").html($('#pname').val()).appendTo(row);
$("<td>").html($('#pcat').val()).appendTo(row);
$("<td>").html($('#pprice').val()).appendTo(row);
$("<td>").html("<button class='deleteBtn'>Delete</button>").appendTo(row);
return;
}
function onDeleteRow(e) {
if (!e.target.classList.contains("deleteBtn")) {
return;
}
if (confirm("Are you sure you want to delete this Product?")) {
$(e.target).closest("tr").remove();
}
}
$formEl.on({
submit: onAddProduct
});
$tableEl.on({
click: onDeleteRow
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h4>Add Product</h4><br>
<form>
<label for="pname">Product Name:</label>
<input type="text" id="pname" name="pname">
<label for="pcat">Product Category:</label>
<input type="text" id="pcat" name="pcat">
<label for="pprice">Product price:</label>
<input type="text" id="pprice" name="pprice">
<button type="submit" class="addBtn">Add New</button>
</form>
<table>
<thead>
<tr>
<th>Product Name</th>
<th>Product Category</th>
<th>Product Price</th>
<td> </td>
</tr>
</thead>
<tbody>
</tbody>
</table>
I am not able to replicate the issue with this code. Only 1 Row is added.
Your table is missing the <tbody> around the rows you have added, so the browser is adding it in to create a valid table. This results in 2 <tbody> elements, and is why rows are being added twice:
It can be prevented by putting the header and body rows inside the <thead> and <tbody> elements that the browser wants, seen below in the snippet -
$(function() {
var $formEl = $('form');
var $tbodyEl = $('tbody');
function onAddProduct(e) {
e.preventDefault();
var $pName = $('#pname').val();
var $pCat = $('#pcat').val();
var $pPrice = $('#pprice').val();
$tbodyEl.append(`
<tr>
<td>${$pName}</td>
<td>${$pCat}</td>
<td>${$pPrice}</td>
</tr>
`);
}
$formEl.on({
submit: onAddProduct
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="productTable" border="1">
<thead>
<tr>
<th>Product Name</th>
<th>Product Category</th>
<th>Product Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>M&M</td>
<td>Snacks</td>
<td>$1.99</td>
</tr>
<tr>
<td>Table</td>
<td>Furniture</td>
<td>$1.99</td>
</tr>
<tr>
<td>Kale</td>
<td>Vegetables</td>
<td>$2.49</td>
</tr>
</tbody>
</table>
<h4>Add Product</h4><br>
<form>
<label for="pname">Product Name:</label>
<input type="text" id="pname" name="pname">
<label for="pcat">Product Category:</label>
<input type="text" id="pcat" name="pcat">
<label for="pprice">Product price:</label>
<input type="text" id="pprice" name="pprice">
<button type="submit" class="addBtn">Add New</button>
</form>
I am using multiple text box to insert data into database table. So doing few researches and used online resources to make it work. But stuck into one basic thing, I guess. The issue is with the jQuery mapping. Let me share the code here:
//Add row to the table
$('#btnAddRow').on('click', function() {
var $clone = $('#tblQuesAns tbody tr:last').clone();
$clone.find('input').val('')
$('#tblQuesAns tbody').append($clone);
});
//Add more rows for option
$('body').on('click', '.addOptions', function() {
$(this).parent().append('<div><input class="txtOptions" type="text" /></div>');
});
//Get text box values
$('#btnGetValues').on('click', function() {
const allData = $('#tblQuesAns tbody tr').map(function() {
const $row = $(this),
question = $row.find('.txtQuestion').val(),
options = $row.find('.txtOptions').map(function() {
return this.value;
}).get().join(" ");
//return { question, options };
alert(question + ' ' + options.replace(/\s+/g, "_"));
}).get();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<button id="btnAddRow" type="button">
Add Row
</button>
<button id="btnGetValues" type="button">
Get Values
</button>
<table id="tblQuesAns" border="1">
<thead>
<tr>
<th>Question</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input class="txtQuestion" value="Capital of Englnad" />
</td>
<td>
<input class="txtOptions" value="London" />
<span class="addOptions">(+)</span>
</td>
</tr>
<tr>
<td>
<input class="txtQuestion" value="Current Pandemic" />
</td>
<td>
<input class="txtOptions" value="Corona" />
<span class="addOptions">(+)</span>
</td>
</tr>
</tbody>
</table>
By default, jQuery map uses comma and I tried to remove those by using replace method as follows:
options.join(' ').replace(/\s+/g, "_")
Now I may have options that may contain comma. For example:
Question Options
Question 1 New York
Jakarta
London, Paris
Munich
So problem is, the values having space from text boxes also get replaced with the underscore sign replace(/\s+/g, "_"). So I get this output:
New_York_Jakarta_London,_Paris_Munich
But my expected output is this:
New York_Jakarta_London, Paris_Munich
I tried a different way that works but in this case all the text box values get concatenated:
var options = $("input[name*='txtOptions']");
var str = "";
$.each(options, function(i, item) {
str += $(item).val();
});
The problem with the above is, when I've different questions say question 1, question 2, it'll merge all the options to both of them. Though I want specific options for both questions.
Something like this?
//Add row to the table
$('#btnAddRow').on('click', function() {
var $clone = $('#tblQuesAns tbody tr:last').clone();
$clone.find('input').val('')
$('#tblQuesAns tbody').append($clone);
});
//Add more rows for option
$('body').on('click', '.addOptions', function() {
$(this).parent().append('<div><input class="txtOptions" type="text" /></div>');
});
//Get text box values
$('#btnGetValues').on('click', function() {
const allData = $('#tblQuesAns tbody tr').map(function() {
const $row = $(this),
question = $row.find('.txtQuestion').val(),
options = $row.find('.txtOptions').map(function() {
return this.value;
}).get().join("_");
return {question,options}
}).get()
const x = allData.map(item => `${item.question}_${item.options}`).join(" ")
console.log(x)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<button id="btnAddRow" type="button">
Add Row
</button>
<button id="btnGetValues" type="button">
Get Values
</button>
<table id="tblQuesAns" border="1">
<thead>
<tr>
<th>Question</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input class="txtQuestion" value="Capital of England" />
</td>
<td>
<input class="txtOptions" value="London" />
<span class="addOptions">(+)</span>
</td>
</tr>
<tr>
<td>
<input class="txtQuestion" value="Current Pandemic" />
</td>
<td>
<input class="txtOptions" value="Corona" />
<span class="addOptions">(+)</span>
</td>
</tr>
</tbody>
</table>
I have a table which is loaded from database. When a user updates the text boxes in the table, i have written a jquery which should collect the updated values from the HTML table and wanted to update them back to database. Need help in fixing the jquery to get the updated values from the form. Below written Jquery doesn't give me updated html values when i fill a form and try to run the Jquery.
HTML
<div class="panel-body">
<table id="myTable" class="table table-striped table-hover table-sm" cellspacing="10" width="100%" style="font-size: 14px; height: auto">
<thead>
<tr style="text-align: right;">
<th>Key Type</th>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td>{{result["Key Type"]}}</td>
<td>{{result["Key"]}}</td>
<td><input type="text" value={{result["Value"]}} style="text-align: center;"></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="col-md-4">
<input type="submit" id="Save" align="center" class="btn btn-primary" style="width:150px" value="SAVE">
<input type="reset" id="Reset" align="center" class="btn btn-primary" style="width:150px" value="CANCEL">
</div>
</div>
Jquery
<script type="text/javascript">
$(function () {
var dataArr = [];
$("td").each(function () {
dataArr.push($(this).html());
});
$('#Save').click(function () {
$.ajax({
type: "POST",
headers: { "Content-Type": "application/json" },
url: "/SaveFile",
data: JSON.stringify(dataArr),
success: function (response) {
console.log(response);
},
error: function (response, error) {
console.log(response);
console.log(error);
}
});
});
});
</script>
Changes Made
<script type="text/javascript">
$(function () {
$('#Save').click(function () {
var dataArr = [];
$("td").each(function () {
dataArr.push($(this).html());
});
$.ajax({
type: "POST",
headers: { "Content-Type": "application/json" },
url: "/SaveFile",
data: JSON.stringify(dataArr),
success: function (response) {
console.log(response);
},
error: function (response, error) {
console.log(response);
console.log(error);
}
});
});
});
</script>
I would consider an Array of Objects versus a single Array. If your Table is in this format:
<div class="panel-body">
<table id="myTable" class="table table-striped table-hover table-sm" cellspacing="10" width="100%" style="font-size: 14px; height: auto">
<thead>
<tr style="text-align: right;">
<th>Key Type</th>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td>{{result["Key Type"]}}</td>
<td>{{result["Key"]}}</td>
<td><input type="text" value={{result["Value"]}} style="text-align: center;"></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="col-md-4">
<input type="submit" id="Save" align="center" class="btn btn-primary" style="width:150px" value="SAVE">
<input type="reset" id="Reset" align="center" class="btn btn-primary" style="width:150px" value="CANCEL">
</div>
</div>
Then an Array will contain just a giant list of hard to read data.
Consider the following.
function getTableData(tbl){
var head = $("thead", tbl);
var body = $("tbody", tbl);
var results = [];
var keys = [];
var row;
$("th", head).each(function(i, el){
keys.push($(el).text().trim());
});
$("tr", body).each(function(ri, r){
row = {};
$.each(keys, function(i, k){
if(i < 2){
row[k] = $("td", r).eq(i).text().trim();
} else {
row[k] = $("td", r).eq(i).find("input").val();
}
});
results.push(row);
});
return results;
}
This will give you a more structured dataset. For example, using it like so:
var dataObj = getTableData($("#myTable"));
The dataObj array would contain something like:
[
{
"Key Type": "Number",
"Key": "Product Code",
"Key Value": "1001"
},
{
"Key Type": "Number",
"Key": "Product Code",
"Key Value": "1002"
}
]
Also notice for some cells, we're getting the Text from that cell and the final cell, we have to get the Value from the Input field. If that's the only item you're trying to get an array of, you can simplify the code.
function getTableData(tbl){
var body = $("tbody", tbl);
var results = [];
$("tr", body).each(function(i, r){
results.push($("td:last input", r).val());
});
return results;
}
This will give you an array of all the Inputs. It would be used like:
var dataArr = getTableData($("#myTable"));
I have a datatable. There is a Delete button on every row. As soon as I delete a row using .remove() function the respective row gets deleted, but afterwards on clicking the Save button, the rows below the deleted rows gets undefined.
Here is the sample code:
HTML
<body>
<form method="POST"></form>
<div class="container">
<table cellpadding="0" cellspacing="0" border="0" class="dataTable" id="example">
<thead>
<tr>
<th>Name</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type ="text" id="name_0" value ="hello0"/></td>
<td><button id="btn_0" onclick="del(this);">Delete</button></td>
</tr>
<tr>
<td><input type ="text" id="name_1" value ="hello1"/></td>
<td><button id="btn_1" onclick="del(this);">Delete</button></td>
</tr>
<tr>
<td><input type ="text" id="name_2" value ="hello2"/></td>
<td><button id="btn_2" onclick="del(this);">Delete</button></td>
</tr>
<tr>
<td><input type ="text" id="name_3" value ="hello3"/></td>
<td><button id="btn_3" onclick="del(this);">Delete</button></td>
</tr>
</tbody>
</table>
<input type="button" value="Save" id="btnSave"/>
</div>
</body>
JS:
$(document).ready(function() {
var i =0;
$('#example').dataTable({
"aoColumns": [
null, { "bSortable": false }
],
"aaSorting": [],
"pageLength": 10,
"lengthMenu": [5, 10, 25, 50, 100, 200]
});
$('#btnSave').click(function(){
var tbl = $('#example').dataTable();
$(tbl.fnGetNodes()).each(function () {
alert($(this).find("#name_" + i).val());
i++;
});
});
});
function del(element)
{
var btnId = element.id;
var idIndex = btnId.substring(btnId.indexOf("_") + 1);
var table = $('#example').DataTable();
table.row($($("#btn_" + idIndex)).parents('tr')).remove().draw();
}
Here is a non-working Demo for the same.
How can I delete a row and then clicking on the Save button, the rows below the deleted row should not get undefined.
Any assistance would be appreciated.
This happens because there is a mismatch between row index and ID of the INPUT element after you delete the row.
Short workaround would be to use the following code instead:
alert($(this).find("input[type=text]").val());
See updated jsFiddle for code and demonstration.
$(document).ready(function () {
$('#btnSave').click(function () {
$('#example tbody tr').each(function () {
alert($(this).find("td:eq(0)").find('input').val());
});
});
});
function del(element) {
$(element).closest('tr').remove();
}
I've got a table with a checkbox in each row, like this:
<table id='users'>
<thead>
...
</thead>
<tbody>
<tr>
<td><input type='checkbox' name='users' id='someUserId'></td>
<td> some variable pid </td>
<td>...</td>
</tr>
<tr>
<td><input type='checkbox' name='users' id='someOtherId'></td>
<td> some other variable pid </td>
<td>...</td>
</tr>
...
</tbody>
</table>
Now i want to put the text of the columns next to the checkboxes, the pids, into an array, then pass the array to a function. The function should take each record in the array and process them.
My best try so far:
function myFunction(arr[]){...}
function getIds(obj){
var $table = $("#users");
alert($table.attr("id"));
var $cboxes = $table.find("input:checkbox").toArray();
alert($cboxes);
var checkedArray = [];
var pid;
for(i = 0;i < $cboxes.length; i++){
if($cboxes[i].checked){
pid = $cboxes.parent().siblings().eq(0).text();
checkedArray.push(pid);
alert(pid);
}
}
alert(checkedArray);
return checkedArray;
}
$("#button").click(function(){
var ids = getIds();
for(i = 0; i < ids.length; i++){
myFunction(ids[i]);
alert("Function executed for "+ids[i]+".");
}
});
You can slim this down heavily with the :checked pseudo-selector, and $.map.
function process (id) {
alert(id);
}
function find () {
return $('#users').find('input:checkbox:checked').map(function () {
return $(this).parent().next().text();
}).toArray();
}
function handle () {
find().forEach(process);
}
$('#btn').on('click', handle); // Pseudo-event
<table id='users'>
<thead>
</thead>
<tbody>
<tr>
<td><input type='checkbox' name='users' id='someUserId'></td>
<td> some variable pid </td>
<td>...</td>
</tr>
<tr>
<td><input type='checkbox' name='users' id='someOtherId'></td>
<td> some other variable pid </td>
<td>...</td>
</tr>
</tbody>
</table>
<button id="btn">Check!</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
If you don't want to loop twice, you should compress the logic into a single function chain. This cuts down on loops, but still builds the array for later use.
var myNamespace = {};
function process (id) {
alert('Single ID: '+ id);
return id;
}
function find () {
return $('#users').find('input:checkbox:checked').map(function () {
return process($(this).parent().next().text());
}).toArray();
}
function handle () {
myNamespace.ids = find();
alert('All IDs: ' + myNamespace.ids)
}
$('#btn').on('click', handle); // Pseudo-event
<table id='users'>
<thead>
</thead>
<tbody>
<tr>
<td><input type='checkbox' name='users' id='someUserId'></td>
<td> some variable pid </td>
<td>...</td>
</tr>
<tr>
<td><input type='checkbox' name='users' id='someOtherId'></td>
<td> some other variable pid </td>
<td>...</td>
</tr>
</tbody>
</table>
<button id="btn">Check!</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Try this:
fiddle
function getIds() {
var chk = $("#users").find("input:checkbox");
var pId = [];
chk.each(function(){
pId.push($(this).parent().next().html());
});
return pId;
}
$(function(){
getIds().forEach(function(i){
console.log(i);
});
});
Find all checkboxes inside the users table, create array, push all pId's into the array then return it from the function. Then just loop through them all.