Add and delete table row with pure javascript - javascript

I would like to create a table with row count. Currently with the code I have now the row count is not update after delete in the middle row. I found this and try to apply on my code but it doesn't work for updating row count.
Here is the snippet that able to add and delete.
function add(addrow){
var id=document.getElementById('addrow').getElementsByTagName('tbody')[0];
var count=id.rows.length;
var newrow=id.insertRow();
newrow.innerHTML='<td>'+count+'</td><input type="text" name="textbox"><td></td><td><div onclick="del(this)">Delete</div></td>';
}
function del(btn) {
var deleterow = btn.parentNode.parentNode;
deleterow.parentNode.removeChild(deleterow);
}
<button type="button" onclick="add('addrow')">Add</button>
<table id="addrow">
<thead>
<tr>
<th>No</th>
<th>Text</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
</tr>
</tbody>
</table>

You can get the last row's id as max_id, then assign new row's value to max_id + 1.
Pseudo-code:
let last_row = table.rows[table.rows.length] - 1;
let max_id = last_row.id;
// create new_row
new_row.id = max_id + 1;

You will need to loop over all rows after the removed row and decrement their counts by one.
var id=document.getElementById('addrow').getElementsByTagName('tbody')[0];
function add(addrow){
var count=id.rows.length;
var newrow=id.insertRow();
newrow.innerHTML='<td>'+count+'</td><input type="text" name="textbox"><td></td><td><div onclick="del(this)">Delete</div></td>';
}
function del(btn) {
var deleterow = btn.parentNode.parentNode;
var num = +deleterow.querySelector("td").textContent;
deleterow.parentNode.removeChild(deleterow);
for(let i = num; i < id.rows.length; i++){
id.rows[i].querySelector("td").textContent--;
}
}
<button type="button" onclick="add('addrow')">Add</button>
<table id="addrow">
<thead>
<tr>
<th>No</th>
<th>Text</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
</tr>
</tbody>
</table>

try this
function add(addrow){
var id=document.getElementById('addrow').getElementsByTagName('tbody')[0];
var count=id.rows.length+1;
var newrow=id.insertRow();
newrow.innerHTML='<td>'+count+'</td><input type="text" name="textbox"><td></td><td><div onclick="del(this)">Delete</div></td>';
}
function del(btn) {
var deleterow = btn.parentNode.parentNode;
deleterow.parentNode.removeChild(deleterow);
let i = 1;
Array.from(document.querySelector('tbody').children).map(child =>{
child.children[0].innerHTML = i;
i++;
})
}
<button type="button" onclick="add('addrow')">Add</button>
<table id="addrow">
<thead>
<tr>
<th>No</th>
<th>Text</th>
<th>Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>

You need to update the No column of the table when any row is deleted.
Heres' one way of doing it:
const btn = document.querySelector('button');
const tbody = document.getElementById('addrow').querySelector('tbody');
btn.addEventListener('click', () => {
// add new row in table body
const newRow = tbody.insertRow();
// get the length of rows after adding the new row
const count = tbody.rows.length;
// add columns in the newly added row
const newCell = newRow.insertCell(0);
newCell.textContent = count;
const newCell2 = newRow.insertCell(1);
newCell2.innerHTML = '<input type="text" name="textbox">';
const newCell3 = newRow.insertCell(2);
newCell3.innerHTML = `<button id="del" data-row="${count}">Delete</button>`;
});
// listen for click event on delete button of all the rows
tbody.addEventListener('click', (e) => {
if (e.target.matches('#del')) {
// delete the row using the value of 'data-row' attribute of the delete button
tbody.parentElement.deleteRow(e.target.dataset.row);
updateTableRowCount();
}
});
// update row count when any row is deleted
function updateTableRowCount() {
[...tbody.children].forEach((row, idx) => {
// update 'No' column value
row.firstElementChild.textContent = idx + 1;
// update `data-row` attribute of the delete button
row.lastElementChild.firstElementChild.setAttribute('data-row', idx + 1);
});
}
<button>Add</button>
<table id="addrow">
<thead>
<tr>
<th>No</th>
<th>Text</th>
<th>Action</th>
</tr>
</thead>
<tbody></tbody>
</table>

Related

For loop inside for loop not working properly repeating same values multiple times Javascript

I'm wanting every <tbody> tag will be gone as object index like first <tbody>->1 and second <tbody>-> 2 then inside the <tbody> every <tr> will be another object and that will be store into the <tbody> object and last the last part every <td> should have object key ("eiin", "name") inside the <tr> object
I'm trying using for loop multiple times but the console.log showing me okay but first object repeated 2 times.
Html
<section class="institute_list">
<table class="table" border="1">
<thead>
<tr>
<th scope="col">EIIN</th>
<th scope="col">Institute</th>
</tr>
</thead>
<tbody>
<tr>
<td>000000</td>
<td>Name</td>
</tr>
</tbody>
<tbody>
<tr>
<td>111111</td>
<td>Name 2</td>
</tr>
</tbody>
</table>
</section>
Javascript & jQuery
<script>
var rows = '', the_row='', the_xrow={}, tr_values={}, xtd_obj={};
tbodys = ($(".institute_list .table tbody").length);
for( var x=0; tbodys > x; x++) {
rows = $('.institute_list .table tbody:nth-child('+(x+1)+') tr').length;
the_row = '.institute_list .table tbody:nth-child('+(x+1)+') tr:nth-child(';
for( var i=1; rows >= i; i++ ){
tr_values = {
'eiin' : $(the_row+i+') td:first-child').text(),
'name' : $(the_row+i+') td:nth-child(2)').text()
};
the_xrow[i] = tr_values;
}
xtd_obj[x] = the_xrow;
}
console.log(xtd_obj);
</script>
and i'm getting this output in console
here
You may try the code below. You can separate every <tbody>,<tr>,<td> tag as a loop then make them a array.
var target = $(".institute_list > table");
var output = [];
$(target).find("tbody").each(function(i){
output[i] = {};
$(this).children().each(function(j){
output[i][j] = {};
$(this).children().each(function(k, td){
if ( k == 0 ) {
output[i][j]["eiin"] = $(td).text();
} else if ( k == 1 ) {
output[i][j]["name"] = $(td).text();
} else {
output[i][j][k] = $(td).text();
}
});
});
});
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="institute_list">
<table class="table" border="1">
<thead>
<tr>
<th scope="col">EIIN</th>
<th scope="col">Institute</th>
</tr>
</thead>
<tbody>
<tr>
<td>000000</td>
<td>Name</td>
</tr>
</tbody>
<tbody>
<tr>
<td>111111</td>
<td>Name 2</td>
</tr>
</tbody>
</table>
</section>
First, you need a closing </tbody> tag around the first element. Second I think you might be running into a scoping problem. You are defining the_xrow and tr_values outside of the for loops instead of inside of the for loops.
<script>
var xtd_obj={};
var tbodys = ($(".institute_list .table tbody").length);
for( var x=1; tbodys >= x; x++) {
var current_row = '.institute_list .table tbody:nth-child('+x+') tr';
var rows = $(current_row).length;
var the_row = current_row + ':nth-child(';
var the_xrow = {};
for( var i=1; rows >= i; i++ ){
the_xrow[i] = {
'eiin' : $(the_row+i+') td:first-child').text(),
'name' : $(the_row+i+') td:nth-child(2)').text()
};
}
xtd_obj[x] = the_xrow;
}
console.log(xtd_obj);
</script>
It's working for me
<script>
var rows = '', the_row='', xtd_obj={};
var tbodys = ($(".institute_list .table tbody").length)+1;
for( var x=1; tbodys > x; x++) {
rows = $('.institute_list .table tbody:nth-child('+(x+1)+') tr').length;
the_row = '.institute_list .table tbody:nth-child('+(x+1)+') tr:nth-child(';
var the_xrow = {};
for( var i=0; rows > i; i++ ){
var tr_values = {
'eiin' : $(the_row+i+1+') td:first-child').text(),
'name' : $(the_row+i+1+') td:nth-child(2)').text()
};
the_xrow[i] = tr_values;
}
xtd_obj[x] = the_xrow;
}
console.log(xtd_obj);
</script>
Here's the screenshot

Unselect highlighted row

I have this table, and I can't seem to find out how to unselect marked field, if it's clicked again? So a double-click on id 2 would select->unselect.
function highlight_row() {
var table = document.getElementById('testresultsTable');
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function () {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
rowsNotSelected[row].style.backgroundColor = "";
rowsNotSelected[row].classList.remove('selected');
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
rowSelected.style.backgroundColor = "yellow";
rowSelected.className += " selected";
}
}
} //end of function
window.onload = highlight_row;
<table id="testresultsTable">
<thead>
<th>ID</th>
<th>Tests</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>TESTRUN1</td>
</tr>
<tr>
<td>2</td>
<td>TESTRUN2</td>
</tr>
<tr>
<td>3</td>
<td>TESTRUN3</td>
</tr>
</tbody>
</table>
I thought about making some kind of count on the rowID, so if it's clicked more than once after each other, then it would toggle between select/unselect?
You can solve it by doing something similar to this, this will first check the selected row for the selected class and remove it if it is found, otherwise, it'll add it to the row you clicked. After that is done, this function will loop through all other rows, check if they aren't the clicked row and remove the selected state accordingly.
So now once you click, your code will look for selected on the row you clicked, if it is found, it'll remove that class to reset the styling, if it isn't found, it'll add the selected class. After this, the code will check all rows to see if they're not the selected row and style them accordingly.
function highlight_row() {
var table = document.getElementById('testresultsTable');
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function() {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
if(row !== rowId) {
rowsNotSelected[row].style.backgroundColor = "";
rowsNotSelected[row].classList.remove('selected');
}
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
if (rowSelected.classList.contains('selected')) {
rowSelected.style.backgroundColor = "";
rowSelected.classList.remove('selected');
} else {
rowSelected.style.backgroundColor = "yellow";
rowSelected.classList.add("selected");
}
}
}
} //end of function
window.onload = highlight_row;
<table id="testresultsTable">
<thead>
<th>ID</th>
<th>Tests</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>TESTRUN1</td>
</tr>
<tr>
<td>2</td>
<td>TESTRUN2</td>
</tr>
<tr>
<td>3</td>
<td>TESTRUN3</td>
</tr>
</tbody>
</table>
Hope this helps!
function highlight_row() {
var table = document.getElementById('testresultsTable');
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function () {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
if(row!==rowId){
rowsNotSelected[row].style.backgroundColor = "white";
rowsNotSelected[row].classList.remove('selected');
}
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
if(rowSelected.classList.contains("selected")) {
rowSelected.style.backgroundColor = "";
rowSelected.classList.remove("selected");
}
else{
rowSelected.style.backgroundColor = "yellow";
rowSelected.classList.add("selected");
}
}
}
} //end of function
window.onload = highlight_row;
<table id="testresultsTable">
<thead>
<th>ID</th>
<th>Tests</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>TESTRUN1</td>
</tr>
<tr>
<td>2</td>
<td>TESTRUN2</td>
</tr>
<tr>
<td>3</td>
<td>TESTRUN3</td>
</tr>
</tbody>
</table>
I'd do it like this
var selected;
(function () {
var rows = document.querySelectorAll('#testresultsTable > tbody > tr');
rows.forEach(tr => tr.addEventListener('click', () => {
if(selected === tr){
selected.classList.remove('selected');
selected = undefined;
}
else {
if(selected) selected.classList.remove('selected');
selected = tr;
tr.classList.add('selected');
}
}));
})();
tbody > tr {
cursor: pointer;
user-select: none;
}
tr.selected {
background-color: yellow;
}
<table id="testresultsTable">
<thead><th>ID</th><th>Tests</th></thead>
<tbody>
<tr><td>1</td><td>TESTRUN1</td></tr>
<tr><td>2</td><td>TESTRUN2</td></tr>
<tr><td>3</td><td>TESTRUN3</td></tr>
</tbody>
</table>

Javascript sum table conditional

I need to sum values in a two column table, where for each row if col2 is not blank, add it to the total, else instead add col1. Then publish the total to a div
Below is what I've tried but it outputs blank.
var table = document.getElementById("PLTable");
var cost_est = document.getElementsByClassName("cost_estimate");
var act_cost = document.getElementsByClassName("act_cost");
var sum2 = 0;
for (var i = 0, row; row = table.rows[i]; i++) {
if (act_cost[i].innerText>0) {
sum2 += act_cost[i].innerText;
}
else {
sum2 += cost_est[i].innerText;
}
}
document.getElementById("cost_projected_total").innerHTML = sum2
<!--HTML data looks like this:-->
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost"></td>
</tr>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost">50</td>
</tr>
</table>
<div id="cost_projected_total">
</div>
Correct output should be sum2 = 150 & that result should be output inside the div.
Any ideas?
There are some points to address in your code.
I will try to summarize what was wrong and how it should be change:
table.rows actually loops the head as well, so your index would go out of bounds.
innerText returns a text, so you first need to conver that value to a Number first, otherwise it will concatenate the strings.
So, basically, what I did to keep your code as it currently was is:
added a tbody
changed table.rows to the count of the tbody rows.
Acquired both numeric values of the looped items.
Below is the working code with the mentioned changes and fixes, it could've been way shorted, I just want to keep the code as close to your so that you can understand where and what was wrong, without necessarely relying on an optimal solution.
var table = document.getElementById("PLTable");
var tbody = table.getElementsByTagName('tbody')[0];
var cost_est = document.getElementsByClassName("cost_estimate");
var act_cost = document.getElementsByClassName("act_cost");
var sum2 = 0;
for (var i = 0; i < tbody.getElementsByTagName('tr').length; i++) {
var row_act_cost = Number(act_cost[i].innerText);
var row_cost_est = Number(cost_est[i].innerText);
if (row_act_cost > 0) {
sum2 += row_act_cost;
}
else {
sum2 += row_cost_est;
}
}
document.getElementById("cost_projected_total").innerHTML = sum2;
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tbody>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost"></td>
</tr>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost">50</td>
</tr>
</tbody>
</table>
<div id="cost_projected_total">
</div>
Loop through act_cost and check if the text in each cell is a valid and > 0 number then add it to sum2 otherwise add the cost_est at that index to sum2.
const table = document.getElementById("PLTable"),
cost_est = document.querySelectorAll(".cost_estimate"),
act_cost = document.querySelectorAll(".act_cost"),
total = document.getElementById("cost_projected_total");
let sum2 = 0;
/** loop through the "act_cost" (2nd column) **/
/**
* el: current td from "act_cost".
* i: its index in "act_cost"
**/
act_cost.forEach((el, i) => sum2 += +el.textContent > 0 ? +el.textContent:+cost_est[i].textContent);
/** "+" transforms the text into a number if possible **/
total.textContent = 'Total: ' + sum2;
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tr>
<td class="cost_estimate">100</td>
<td class="act_cost"></td>
</tr>
<tr>
<td class="cost_estimate">100</td>
<td class="act_cost">50</td>
</tr>
</table>
<div id="cost_projected_total"></div>

Get nested array items to append to new column in HTML Table

I'm trying to append items from a 2D array into a table, but everything is appearing in the one column on the left. How can I separate tableDataArr[1] to start loading into the next column across?
Javascript
let names = []; //populated dynamically
let language = []; //populated dynamically
let tableDataArr = [names, language];
function renderData() {
for (let i = 0; i < tableDataArr.length; i++) {
tableDataArr[i].forEach(j => {
let newRow = document.createElement("tr");
newRow.className = "row";
newRow.innerHTML = `<td class='cell'>${j}</td>`;
leftTable.appendChild(newRow);
});
}
}
HTML
<div class='left-tbl-wrap'>
<table class='table' id='left-table'>
<tr class='row'>
<th class='th'>Name</th>
<th class='th'>Language</th>
<th class='th'>Latest tag</th>
<th class='th'><span class='delete'></span></th>
</tr>
</table>
</div>
For each iteration add name and language to the same row, then insert that row into table.
I added some elements in names and languages array to demostrate
let names = ["name1", "name2", "name3"]; //populated dynamically
let language = ["language1", "language2", "language3"]; //populated dynamically
let tableDataArr = [names, language];
const leftTable = document.querySelector("#left-table");
function renderData() {
tableDataArr[0].forEach((j, i) => {
let newRow = document.createElement("tr");
newRow.className = "row";
newRow.innerHTML = `<td class='cell'>${j}</td><td class='cell'>${tableDataArr[1][i]}</td>`;
leftTable.appendChild(newRow);
});
}
renderData();
<div class='left-tbl-wrap'>
<table class='table' id='left-table'>
<tr class='row'>
<th class='th'>Name</th>
<th class='th'>Language</th>
<th class='th'>Latest tag</th>
<th class='th'><span class='delete'></span></th>
</tr>
</table>
</div>
It should be like that
function renderData() {
for (let i = 0; i < tableDataArr.length; i++) {
let newRow = document.createElement("tr");
tableDataArr[i].forEach(j=> {
newRow.className = "row";
newRow.innerHTML = `<td class='cell'>${j}</td>`;
leftTable.appendChild(newRow);
});
}
}
Because you may do not need to iterate table row in the second loop. If you do like that it will be add each row with only one table data.

Loop through my table's specific column

html
<table id="myList">
<thead>
<tr>
<td>Product ID</td>
<td>Product Name</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
Javascript
var tableRef = document.getElementById("myList").getElementsByTagName("tbody")[0];
var newRow = tableRef.insertRow(tableRef.rows.length);
var newCell = newRow.insertCell(0);
var otherCell = newRow.insertCell(2);
var check;
var myText = result.text;
var myTextTwo = myText.replace(/['"]+/g, '');
alert(myTextTwo);
for (var i = 0; i < tableRef.rows.length; i++) {
if (myTextTwo != tableRef.rows[i].cells[0].innerHTML) {
check = true
}
else if (myTextTwo == tableRef.rows[i].cells[0].innerHTML) {
tableRef.rows[i].cells[2].innerHTML += 1;
check = false;
break;
}
}
if (check) {
var newText = document.createTextNode(myTextTwo);
var otherText = document.createTextNode("1");
newCell.appendChild(newText);
otherCell.appendChild(otherText);
}
else {
alert("You have scanned this item before.");
}
What I have done is scanning a QR that contains a Product ID(e.g. "123") and insert the Product ID into the column called "Product ID", which I am able to do it.
However, what I am trying to do now is to, if the user scan a QR code that contains the same Product ID(e.g. "123"), my code will be able to detect the duplicate and add onto the quantity.
So what I planned to do is to loop through "Product ID" column and check if there's any duplicate. If there isn't any duplicates, the Quantity for the Product ID would be 1.
Product ID | Product Name | Quantity
123 | Hello | 1
Otherwise, duplicate exist, Quantity would be 2.
Product ID | Product Name | Quantity
123 | Hello | 2
Do you mean something like this?
var tableRef = document.getElementById("myList").getElementsByTagName("tbody")[0];
// save the row number of the existing product
var found = false;
var myText = result.text;
var myTextTwo = myText.replace(/['"]+/g, '');
// search the table for the existing product
for (var i = 0; i < tableRef.rows.length && !found; ++i) {
// if you found it then
if (tableRef.rows[i].cells[0].innerHTML == myTextTwo) {
// update the value
tableRef.rows[i].cells[2].innerHTML += 1;
// and say we found it
found = true;
}
}
// at this point, if we didn't find anything then add a new row
if (!found) {
var newRow = tableRef.insertRow(tableRef.rows.length);
newRow.insertCell(0).innerText = "...";
newRow.insertCell(0).innerText = "...";
newRow.insertCell(0).innerText = 1;
}
<table id="myList">
<thead>
<tr>
<td>Product ID</td>
<td>Product Name</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
I think this might help:
The function duplicateCell returns the number of the row that contains a duplicate on the given column or null if no duplicate found.
The function addOne requires a product ID to check for duplicates, a product Name (if no duplicates are found, the product will need a name, otherwise it is ignored) and it also needs to know what table to work on.
AddOne looks for duplicates using the above function and adds one to the quantity.
I started with 1 car 1 bike and 1 skateboard, added 2 bike (id2) and added 2 rockets (id 4).
var duplicateCell = function(tableId, columnNumber, stringToSearch) {
var myTbody = document.getElementById(tableId).getElementsByTagName("tbody")[0];
var tableRows = myTbody.rows.length;
for (var i = 0; i < tableRows; i++) {
if (myTbody.rows[i].cells[columnNumber].innerHTML.trim() == stringToSearch)
return i
}
return null;
}
function addOne(productId, productName, tableId) {
var myTbody = document.getElementById(tableId).getElementsByTagName("tbody")[0];
var rowIndex = duplicateCell(tableId, 0, productId)
if (rowIndex != null) {
myTbody.rows[rowIndex].cells[2].innerHTML = +myTbody.rows[rowIndex].cells[2].innerHTML.trim() + 1;
} else {
var tableRows = myTbody.rows.length;
var row = document.getElementById(tableId).insertRow();
c1 = row.insertCell(0);
c2 = row.insertCell(1);
c3 = row.insertCell(2);
c1.innerHTML = productId;
c2.innerHTML = productName;
c3.innerHTML = 1;
}
}
addOne("4", "Rocket", "myList")
addOne("4", "Rocket", "myList")
addOne("2", " ", "myList")
<table id="myList">
<thead>
<tr>
<td>Product ID</td>
<td>Product Name</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
<tr>
<td>1 </td>
<td>Car </td>
<td>1 </td>
</tr>
<tr>
<td>2 </td>
<td>Bike </td>
<td>1 </td>
</tr>
<tr>
<td>3 </td>
<td>Skateboard </td>
<td>1 </td>
</tr>
</tbody>
</table>

Categories