Pure javascript delete selected rows in html table [duplicate] - javascript

This question already has answers here:
Why does firstChild not return the first element?
(5 answers)
Closed 5 years ago.
I am trying to deleted selected or all rows using pure javascript. I am unable to delete selected rows. what was the issue in my fiddle
Edit: First row is header so not considering that.
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById("links-list").rows;
var checkedIndexes = [];
for (var i = 1; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i] && tableRows[i].cells[0].firstChild.checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = 0; k < checkedIndexes.length; k++) {
tableRef.deleteRow(checkedIndexes[k]);
}
});

This sould be something like the one below, with tableRows[i].querySelector('input').checked, as .firstChild is a textnode. Also, index of tableRows starts with 0.
document.getElementById('delete').addEventListener('click', function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById('links-list').rows;
var checkedRows = [];
for (var i = 0; i < tableRows.length; i++) {
if (tableRows[i].querySelector('input').checked) {
checkedRows.push(tableRows[i]);
}
}
for (var k = 0; k < checkedRows.length; k++) {
checkedRows[k].parentNode.removeChild(checkedRows[k]);
}
});
As the last loop alters the dom, deleting based on indexes is not reliable when multiple rows are deleted in the same time. So instead of the pure indexes, it should iterate through the actual nodes.

You can use the document.querySelectorAll method with the proper css selector to get all the checkboxes that are checked. Then from the table you can remove those rows with checked checkboxes.
let tableRef = document.getElementById('links-list');
let tbody = tableRef.querySelector("tbody");
let checkedInputs = document.querySelectorAll("input[type='checkbox']:checked");
Array.prototype.slice.call(checkedInputs)
.forEach( input => tbody.removeChild(input.parentNode.parentNode))
Can also be writen with es7 syntax like this
[...checkedInputs].forEach( input => tbody.removeChild(input.parentNode.parentNode))

Use the children property instead of the firstChild one. Also you can enhance your code by avoiding element recalculation. For example, you already found the table, so get the row from it.
Also when you're removing rows, start from the end and go up.
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = tableRef.rows;
var checkedIndexes = [];
for (var i = 0; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i].cells[0].children[0].checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = checkedIndexes.length - 1; k >= 0; k--) {
tableRef.deleteRow(checkedIndexes[k]);
}
});
<table id="links-list">
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test1
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test2
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test3
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test4
</td>
</tr>
<tr>
<td>
<input type=checkbox>
</td>
<td>
Test5
</td>
</tr>
</table>
<input type=button value="delete" id="delete">

You have 2 errors, first you are not getting the value correctly; secondly, you are deleting in the list that you are iterating, so you need to fix that. Try this:
document.getElementById("delete").addEventListener("click", function() {
var tableRef = document.getElementById('links-list');
var tableRows = document.getElementById("links-list").rows;
var checkedIndexes = [];
for (var i = 1; i < tableRows.length; i++) {
var checkboxSelected = tableRows[i] && tableRows[i].cells[0].firstElementChild.checked;
if (checkboxSelected) {
checkedIndexes.push(i);
}
}
for (var k = 0; k < checkedIndexes.length; k++) {
tableRef.deleteRow(checkedIndexes[k]-k);
}
});
fiddle

Related

Changing html table row values indexes with pure Javascript

I have a scenarion where I delete rows in a html table. Once the row is deleted, I am trying to realign/sort the hidden fields indexes.
for example if second row with hidden fields name[1]abc tr is deleted, then I am trying to generate table with rows having hidden fields with index name[0] and name[1] etc., Any pointers ?
My fiddle
<table class="links-list">
<tbody>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[0]abc">
<input type="hidden" name="name[0]def">
<input type="hidden" name="name[0]gh1">
</tr>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[1]abc">
<input type="hidden" name="name[1]def">
<input type="hidden" name="name[1]gh1">
</tr>
<tr>
<td>test1</td>
<td>test2</td>
<input type="hidden" name="name[2]abc">
<input type="hidden" name="name[2]def">
<input type="hidden" name="name[2]gh1">
</tr>
</tbody>
</table>
Javascript
//Loop through table rows
//get all hidden fields for each row
// update index value inside name[index] in sorted order
// like all hidden fields with name[0] in first row name[1] for second row etc
function updateHyperlinkIndexes() {
var linksList = document.querySelector('.links-list tbody');
for (var i = 1; i < linksList.children.length; i++) {
var trContent = linksList.children[i];
for (var i = 0; i < trContent.children.length; i++) {
if (trContent.children.item(i).type && trContent.children.item(i).type === "hidden") {
var cellName = trContent.children.item(i).name;
trContent.children.item(i).name = cellName.replace(/[.*]/, i);
}
}
}
return linksList;
};
var updatedHtml = updateHyperlinkIndexes();
Found the problem, PFB working updateHyperlinkIndexes() function.
var linksList = document.querySelector('.links-list tbody');
for (var i = 0; i < linksList.children.length; i++) {
var trContent = linksList.children[i];
for (var j = 0; j < trContent.children.length; j++) {
console.log(trContent.children[j]);
if (trContent.children.item(j).type && trContent.children.item(j).type === "hidden") {
var cellName = trContent.children.item(j).name;
trContent.children.item(j).name = cellName.replace(/\[.*?\]/g, '['+i+']');
}
}
}
Changes made include correction of replace regex expression, it should be replace(/\[.*?\]/g, '['+i+']');. And secondly you used same variable i for iterating nested loops.
Hope it helps you.

Compare participants in one column of the table and make sum from other column, js

I have a table. I'd like to compare participants. If participant have several result points in the table, the script has to return sum of all participant's results. And so on for every participant.
The table is generated from database (".$row["pnt"]."".$row["station"]."".$row["res"]."):
Participant Station Points
aa Some1 1
dd Some1 2
aa sm2 3
dd sm2 4
bb sm3 5
ee sm3 6
For example I've to recieve such a new table:
aa - 4,
dd - 6,
bb - 5,
ee - 6
I've tried to do so:
$(document).ready(function () {
$("body").click(function () {
var rows = $("tbody tr");
var jo = [];
for (var i = 0; i < rows.length; i++) {
for (var j = 1; j <= rows.length; j++) {
var pnt1 = $(rows[i]).find(".pnt").html();
var stations1 = $(rows[i]).find(".station").html();
var pntR1 = $(rows[i]).find(".res").html();
if (pnt1 == $(rows[j]).find(".pnt").html()) {
pntR1 = parseInt(pntR1);
pntR2 = parseInt($(rows[j]).find(".res").html());
jo.push(pnt1, pntR1, pntR2);
break;
}
}
}
console.log(jo);
});
});
But I understood that I'm on a wrong way. Please, help me. I really appreicate if some one could help me on this issue.
Updated after comments:
<table id="pntsRes">
<thead>
<tr>
<th>Участники</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr><td class="pnt">aa</td><td class="station">AES</td><td class="res">1</td></tr><tr><td class="pnt">dd</td><td class="station">AES</td><td class="res">2</td></tr>
<tr><td class="pnt">aa</td><td class="station">Science</td><td class="res">3</td></tr>
<tr><td class="pnt">dd</td><td class="station">Science</td><td class="res">4</td></tr><tr><td class="pnt">bb</td><td class="station">Аэродром</td><td class="res">5</td></tr>
<tr><td class="pnt">ee</td><td class="station">aeroport</td><td class="res">6</td></tr></tbody>
</table>
First, I would consider breaking your solution into three functions - one to extract the data from the HTML (which is a questionable practice in itself), one to transform the data, and one to output the new table. This way, your code is much more maintainable.
function getData() {
var rows = $("tbody tr");
var data = [];
rows.each(function(idx, row){
var pnt = row.find('.pnt').html(),
station = row.find('.station').html()),
res = parseInt(row.find('.res').html());
data.push(pnt, station, res);
});
}
Then I would consider something like this for the second method
// Pass the output from getData() into processData()
function processData(data){
var groupedKeys = {};
var groupedData = data.map(function(datum){
var name = datum[0];
var value = datum[2];
groupedKeys[name] = (groupedKeys[name] || 0) + (value || 0);
});
var transformedData = [];
Object.keys(groupedKeys).forEach(function(key){
transformedData.push([key, groupedKeys[key]]);
});
return transformedData;
}
The last method of course would need to be implemented by yourself, there's a ton that could be improved here, but it could be a good start.
I used an associative array (which is just an object in JavaScript) shown below:
http://jsfiddle.net/a5k6w300/
Changes I made:
var jo = [];
changed to an object instead of an array
var jo = {};
I also added the if(isNaN(object[key]) inside the inner loop in order to make sure that these didn't show as NaN as I continued adding them together.
$(document).ready(function () {
$("body").click(function () {
var rows = $("tbody tr");
var jo = {};
console.log(rows);
for (var i = 0; i < rows.length; i++) {
for (var j = 1; j <= rows.length; j++) {
var pnt1 = $(rows[i]).find(".pnt").html();
var stations1 = $(rows[i]).find(".station").html();
var pntR1 = $(rows[i]).find(".res").html();
if (pnt1 == $(rows[j]).find(".pnt").html()) {
pntR1 = parseInt(pntR1);
pntR2 = parseInt($(rows[j]).find(".res").html());
if(isNaN(jo[pnt1])){
jo[pnt1] = 0;
}
jo[pnt1] += pntR1;
break;
}
}
}
console.log(jo);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="pntsRes">
<thead>
<tr>
<th>Участники</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr>
<td class="pnt">aa</td>
<td class="station">AES</td>
<td class="res">1</td>
</tr>
<tr>
<td class="pnt">dd</td>
<td class="station">AES</td>
<td class="res">2</td>
</tr>
<tr>
<td class="pnt">aa</td>
<td class="station">Science</td>
<td class="res">3</td>
</tr>
<tr>
<td class="pnt">dd</td>
<td class="station">Science</td>
<td class="res">4</td>
</tr>
<tr>
<td class="pnt">bb</td>
<td class="station">Аэродром</td>
<td class="res">5</td>
</tr>
<tr>
<td class="pnt">ee</td>
<td class="station">aeroport</td>
<td class="res">6</td>
</tr>
</tbody>
</table>

Traverse the HTML document

I am using the following code to traverse one forum
var formWithTable = document.getElementsByTagName("table")[0];
var table = formWithTable.getElementsByTagName("tbody")[0];
var rows = table.getElementsByTagName("tr");
for(i = 0; i < rows.length; i++)
{
var cols = rows[i].getElementsByTagName("td");
for (j = 0; j < cols.length; j++)
{
...
}
}
The HTML document is as follows:
<div>
<table class="inventory sortable" id="listContainer_datatable" summary="Properties of various threads" title="Properties of various threads">
<thead>
<tr>
...
<tbody id="listContainer_databody">
<tr id="listContainer_row:0" class="">
<td class="smallCell" valign="top">
<input type="checkbox" name="formCBs" value="2161433" id="listContainer_formCBs2161433" title="Add a new message." />
<label for="listContainer_formCBs2161433" id="listContainer_formCBs2161433Label" class="hideoff">
</label>
</td>
...
</table>
</div>
However, I do not know that why document.getElementsByTagName("table")[0] returns "undefined".
Any help is very appreciated.
What you really should be using is jQuery. Then you can just do this:
$("table")[0]
to select the first table of the document. Simple as that.
In other news, if that is your document, it isn't valid HTML, so Javascript DOM isn't guaranteed to work.
Your script is fine, the only problem might be the script is added before the table is added to the dom, that could be the cause of the problem.
The solution is to move the script to window.onload
window.onload = function(){
var formWithTable = document.getElementsByTagName("table")[0];
var table = formWithTable.getElementsByTagName("tbody")[0];
var rows = table.getElementsByTagName("tr");
for(i = 0; i < rows.length; i++) {
var cols = rows[i].getElementsByTagName("td");
for (j = 0; j < cols.length; j++) {
console.log(cols[j].innerHTML)
}
}
}
Demo: Fiddle

Show, hide and group columns in jQuery

I have a table and I need to group columns. How is it possible with HTML to tell if columns belong together? I've been looking at colgroup, but I don't know if that's what I need.
I need to create a function with jquery which works somehow like Microsoft Excel's group function, so I can hide unused columns and only show the relevant columns, but also the option to show the other columns.
Take a look at the jqGrid demos. It has functionality for grouping columns and, I believe (at least for older versions) also hiding them.
You could try something like this...
HTML
<table>
<tr>
<td>
First Name
</td>
<td>
Middle Initial
</td>
<td>
Last Name
</td>
</tr>
<tr>
<td>
John
</td>
<td>
C
</td>
<td>
Doe
</td>
</tr>
<tr>
<td>
Jim
</td>
<td>
D
</td>
<td>
Doe
</td>
</tr>
<tr>
<td>
Jane
</td>
<td>
E
</td>
<td>
Doe
</td>
</tr>
</table>
<a onclick="javascript:hideColumn('first')">Hide First Name</a>
<a onclick="javascript:hideColumn('middle')">Hide Middle Initial</a>
<a onclick="javascript:hideColumn('last')">Hide Last Name</a>
JavaScript
<script type="text/javascript">
function hideColumn(column) {
var row = [];
var dataCell = [];
switch (column) {
case 'first': {
var a = document.getElementsByTagName('a');
if(a[0].innerHTML == "Hide First Name")
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[0].style.visibility = "hidden";
}
a[0].innerHTML = "Show First Name";
}
else
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[0].style.visibility = "visible";
}
a[0].innerHTML = "Hide First Name";
}
break;
}
case 'middle': {
var a = document.getElementsByTagName('a');
if(a[1].innerHTML == "Hide Middle Initial")
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[1].style.visibility = "hidden";
}
a[1].innerHTML = "Show Middle Initial";
}
else
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[1].style.visibility = "visible";
}
a[1].innerHTML = "Hide Middle Initial";
}
break;
}
case 'last': {
var a = document.getElementsByTagName('a');
if(a[2].innerHTML == "Hide Last Name")
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[2].style.visibility = "hidden";
}
a[2].innerHTML = "Show Last Name";
}
else
{
row = document.getElementsByTagName('tr');
for(var i = 0; i < row.length; i++){
dataCell = row[i].getElementsByTagName('td');
dataCell[2].style.visibility = "visible";
}
a[2].innerHTML = "Hide Last Name";
}
break;
}
}
}
</script>
Since you want to group items by the columns they are in, they will always be in the same spot in the row. There is probably a better/less hardcoded way to do this. But hopefully this example will help.

Find if a cell contents appears more than once

I have a table body that looks like the following:
<tbody>
<tr class="basket_main">
<td class="basket_item">
<input type="text" class="basket_qty_txt" id="ctl00_ctl00_main_body_content_main_content_area_shopping_basket_ctl01_txt_qty_162" value="3" name="ctl00$ctl00$main_body_content$main_content_area$shopping_basket$ctl01$txt_qty_162">
</td>
<td class="basket_item prod_code" id="ctl00_ctl00_main_body_content_main_content_area_shopping_basket_ctl01_prod_code_col">
CSM160
</td>
<td class="basket_item">
SIL.MTG:RENAULT R19 1988 ON
</td>
<td class="basket_item max_qty">
5
</td>
<td class="basket_item">
<input type="button" class="basket_item_button">
<input type="button" class="basket_item_button">
</td>
</tr>
</tbody>
There could be many rows in this table, what I'm trying to find out is if the prod_code appears in more than one row in the table using javascript or jquery.
Iterate through the table cells and collect the data.
Live demo http://jsfiddle.net/kEAzB/6/
var items = {};
$('tr td.basket_item.prod_code').each(function(){
var value = $(this).text();
if (items[value] == undefined) {
items[value] = 0;
}
items[value] += 1;
});
for (key in items) {
alert(key + ":" +items[key]);
}
You could scan all the table rows, store the product codes in an Associative Array (ie productCodes and check if the same product code is already defined.
var productCodesTds = document.getElementsByClassName("prod_code"),
productCodes = Object.create(null),
max,
i;
for (i = 0, max = productCodesTds; i < max; i += 1) {
productCode = productCodesTds[i].innerText;
if (productCode in productCodes) {
// the productCode is already defined in an other td
}
else {
productCodes['productCode'] = null;
}
}
push all the codes to array
var arr = new Array();
$('.prod_code').each(function(){
var prod_code = $(this).val();
arr.push(prod_code);
});
sort the array and check if there are duplicate values
var sorted_arr = arr.sort();
var results = [];
for (var i = 0; i < arr.length - 1; i += 1) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
alert("duplicate value"+sorted_arr[i + 1]);
}
}

Categories