Delete table rows that are checked using one button - javascript

As the title suggests, I have created a table which I am populating with a list, and I also have a checkbox next to each element of that table. Finally I have a button labelled Delete. I want to attach that button with the actual delete operation.
Code of the button (it is inside another table):
<tr id="deleteproject" >
<td width="180" align="center" background="ButtonBackground.png"
onclick = "deleteRow('plist')">
<style="text-decoration:none; display:block; width:100%;
height:100%">
<font size="0.5px"><br/></font>
<font id="DeleteProject" face="verdana" color="white">
DELETE</font>
</a>
</td>
</tr>
The table:
<table ID="plist" border="0" cellpadding="0" cellspacing="0" datasrc="#clicklist"
style="WIDTH: 380px">
<tr>
<td id="projline" width="100%" align="left" valign="middle"
style="margin-left: 16px;">
<input type="checkbox" name="AAA"/>
<font size="3" face="Arial">
<a id="proj" href="urn:a">
<span datafld="Name"
style="margin-left: 20px; line-height: 26px;"></span>
</a>
</font>
</td>
</tr>
</table>
rowDelete function in JS:
function deleteRow(tableID) {
try {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
for(var i=0; i<rowCount; i++) {
var row = table.rows[i];
var chkbox = row.cells[0].childNodes[0];
if(null != chkbox && true == chkbox.checked)
{
table.deleteRow(i);
rowCount--;
i--;
}
}
}catch(e)
{
alert(e);
}
}
When I select a checkbox from a row and push the delete button, I get an object error, which I think means something is null or not understood in the JS code.

You must create a proper table first. The table is invalid in HTML5 and in HTML4, the button needs to be inside a table. Please read this article.
When I select a checkbox from a row and push the delete button, I get an object error, which I think means something is null or not understood in the JS code.
I don't know where to start ... looking at the JS, you are trying to target rows by referencing them by the TableRow Object? or ChildNode? Either way, the vague error message you are receiving is because you must reference the elements in the DOM as an object. There are several ways to do so in your situation, for example:
The tr needs to be referenced by what they are: <tr> the tag name.
var All_TR_Tags = document.getElementsByTagName('tr');
Now All_TR_Tags is an array-like object
Please review the demo and ask questions because I can't make a list of what is wrong and what issues that need to be addressed because it would take hours. The demo's styling is not part of the topic, I just used it because it's a default style I use for tables. The structure of the table is important as much as the JS though. The source itself has been extensively annotated. Please do not hesitate to ask if you have any further questions.
Snippet
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>delRows</title>
<style>
.x th {
color: #FFF;
background: #2C7EDB;
padding: 10px;
text-align: center;
vertical-align: middle;
}
.x tr:nth-child(odd) {
background-color: #333;
color: #FFF;
}
.x tr:nth-child(even) {
background-color: #D3E9FF;
color: #333;
}
.x td {
border-style: solid;
border-width: 1px;
border-color: #264D73;
padding: 5px;
text-align: left;
vertical-align: top;
position: relative;
}
.x thead th:first-child {
border-top-left-radius: 6px;
}
.x thead th:last-child {
border-top-right-radius: 6px;
}
.x tbody tr:last-child th:first-child {
border-bottom-left-radius: 6px;
}
.x tbody tr:last-child td:last-child {
border-bottom-right-radius: 6px;
}
th {
width: 30%;
}
th:first-of-type {
width: 10%;
}
table {
width: 80%;
}
</style>
</head>
<body>
<table id="T1" class="x">
<thead>
<tr>
<th>
<input id="btn1" type="button" value="DelRows" onclick="delRows('T1')" )/>
</th>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr id="row1">
<td>
<input id="chx1" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row2">
<td>
<input id="chx2" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row3">
<td>
<input id="chx3" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row4">
<td>
<input id="chx4" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row5">
<td>
<input id="chx5" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row6">
<td>
<input id="chx6" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row7">
<td>
<input id="chx7" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row8">
<td>
<input id="chx8" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row9">
<td>
<input id="chx9" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr id="row10">
<td>
<input id="chx10" type="checkbox" />
</td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
<script>
function delRows(tableID) {
//1| Take the function's argument and reference it as an id.
var table = document.getElementById(tableID);
//2| getElementsByTagName()[0]¹ will find the first† element with the <tbody> tag.
/* †You can use [0] to specify the first tag, [1] for the second tag, etc. <tbody> is the direct parent of all <tr>, so that's why we want a reference to it */
var tb = table.getElementsByTagName('tbody')[0];
//3| Collect all checkboxes that are checked into a NodeList² named 'checked'.
/* querySelectorAll³ is like getElementBy* on steroids. It accepts a selector as a target to reference, the syntax is like CSS or inside a jQuery object $(selector). Notice the ":checked"⁴ pseudoselector */
var checked = document.querySelectorAll('input[type="checkbox"]:checked');
//4| Collect all <tr> in <tbody> into a NodeList named 'rows'.
/* Remember we referenced the <tbody> as var tb on step 2? */
var rows = tb.querySelectorAll('tr');
//5| Iterate through the checked NodeList from step 3.
/* When dealing with arrays and array-like objects, you'll need to use a 'for loop' to iterate (or loop)⁵ 90% of the time. */
for (var i = 0; i < checked.length; i++) {
//6| For every checked checkbox find it's parent's parent and name it 'row'.
/* In the checked NodeList, there are all of the checked checkboxes so on each loop we are finding that particular checkbox's "grandmother". Example:
i = 4 means we are on the 3rd iteration (loop).
checked[4] is the third checked checkbox.
.parentNode⁶ is the parent element of the third checked checkbox--a <td>
The second .parentNode is the parent of the <td> which is a <tr> */
var row = checked[i].parentNode.parentNode;
//7| Remove 'row' from <tbody>
/* removeChild⁷ needs the parent of the element (or node) that you intend to remove. Thinking ahead, we have the parent of all <tr>: tb (a.k.a. <tbody>) from step 2. */
tb.removeChild(row);
//8| At this point, i is i+1 we go back to step 5 as long as "i < checked.length".
/* var i = one loop of steps 6, 7, and 8. It started initially as 0 which by design coincides with the 0 count index of arrays and array-like objects like the NodeList checked. i is then incremented by 1 (i++) thereby completing the loop. As long as i is less than the total amount of checked checkboxes, it will continue looping. */
}
//9| At this point, i is greater than the total amount of checked checkboxes and stops looping thru steps 6, 7, and 8.
/* This is the end of the function. Sometimes you'll see "return false;", but we didn't need it because the click event that starts this function is just a button. If we kept the original markup, that used an anchor, then "return false" would be necessary because an anchor by default will jump to a location which is undesirable if you are using the anchor as a button instead. */
}
</script>
</body>
</html>

Related

Using drop-down list to change multiple values in separate table cells

I have a table with 3 "main" cells (2 more tables nested inside 2 of these cells; I enabled a blue border around the cells in case it helps visually): Category (top, spanning across 2 columns), Title/Subtitle (left column), and Result (right column).
The left column does not (and should not) change at all. In the Category cell at top, there is a drop-down list and my goal is for when a category is selected, it should update all cells down the right column.
code:
#tablemobile {
/*width: 100%;*/
}
#tmcategory {
text-align: center;
}
.tmsubtitle {
color: blue;
font-style: italic;
}
.tmtitle {
font-weight: bold;
}
.left {
display: inline-block;
float: left;
}
.right {
display: inline-block;
}
#tablemobile td {
height: 80px;
vertical-align: middle;
padding: 2px;
border: 1px solid blue;
}
<form id="tablemobile" action="" method="post">
<table>
<tr>
<td colspan="2" id="tmcategory">
<b>Category:</b>
<select id="columns" onchange="document.getElementById('row1').innerHTML=this.value">
<option value="Result A"> Category 1 </option>
<option value="Result B"> Category 2 </option>
<option value="Result C"> Category 3 </option>
</select>
</td>
</tr>
<tr>
<td>
<table class="left">
<tr>
<td>
<span class="tmtitle">Row 1 Title</span><br><span class="tmsubtitle">Row 1 Subtitle</span>
</td>
</tr>
<tr>
<td>
<span class="tmtitle">Row 2 Title</span><br><span class="tmsubtitle">Row 2 Subtitle</span>
</td>
</tr>
<tr>
<td>
<span class="tmtitle">Row 3 Title</span><br><span class="tmsubtitle">Row 3 Subtitle</span>
</td>
</tr>
</table>
</td>
<td>
<table class="right">
<tr>
<td>
<span id="row1">Result A</span>
</td>
</tr>
<tr>
<td>
<span id="row2">Result D</span>
</td>
</tr>
<tr>
<td>
<span id="row3">Result G</span>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
I have only been able to accomplish this change for the first row because I'm not sure how to add multiple onChange elements or whatever it is that I need to do here. Any help would be greatly appreciated!
At the end of your html code, before closing the <\body> tag, insert this
<script>
document.getElementById('columns').addEventListener("change", function(){
switch(this.value){
case 'Result A':
document.getElementById('row1').innerHTML='A';
document.getElementById('row2').innerHTML='B';
document.getElementById('row3').innerHTML='C';
break;
case 'Result B':
document.getElementById('row1').innerHTML='D';
document.getElementById('row2').innerHTML='E';
document.getElementById('row3').innerHTML='F';
break;
case 'Result C':
document.getElementById('row1').innerHTML='G';
document.getElementById('row2').innerHTML='H';
document.getElementById('row3').innerHTML='I';
break;
}
})
</script>
This is fine in your case, but if your script is longer, it is recommended to include it in a separate javascript file. For example, create a file like scrpt.js with the code inside, and in the html insert the file like this (in case it is saved in the same directory as the html file.
<script src="./scrpt.js"><\script>

State of Radio Button selection based on another value in same table row

I have a situation where I want to select various options through check-boxes in a table and at the same time select a default row with through a radio button option. (think of it like overall permissions in checkbox, then the default accessed permission in radio box) User can select various options in the checkbox selection, and for those selected options they can then select a main default selection. If a row has its checkbox unchecked then they should not be able to select that radio button on that row.
Looking at the image, one should not be able to click (activate) radio button in row 2 (shop 2) unless checkbox in that row has been selected.
My html for the above image is as follows
<table class="table shopListTable">
<tr>
<th>#Html.DisplayName("Shop Name")</th>
<th>#Html.DisplayName("Allowed")</th>
<th>#Html.DisplayName("Default")</th>
</tr>
#foreach (var item in #ViewBag.ShopList)
{
<tr>
<td>
#item.q_name
</td>
<td>
<input class="checkBox" type="checkbox" id="shopAllowed" name="shopAllowed" value="#item.q_guid" />
#item.q_guid
</td>
<td>
<input class="radioButton" type="radio" id="shopDefault" name="shopDefault" value="#item.q_guid" />
</td>
</tr>
}
</table>
Current attempt on Javascript to detect state of checkbox in that row when you click radio-button is as follows
$(document).ready(function () {
$('input[type=radio]').click(function () {
//var radioButtonValue = this.value;
var row = $(this).closest('tr');
var checkBoxState = row.find('.checkBox').is(":checked");
alert(checkBoxState)
if (checkBoxState == true) {
//allow selection of radion button
}
else {
//do not allow
}
});
});
So far I a can rightly get the status of the checkbox (true/false) on alert(checkBoxState). I suppose all I need at this point is
if (checkBoxState == false) {
//do not select the radio button
}
because selecting the radio button isnt a problem. Its not allowing that selection when state is false that I need to solve.
I suppose all I need at this point is....
Yes, you are right. In order to avoid radio button selection you can call the .preventDefault() method of event handler.
In any case pay attention to duplicated IDs when you generate the table (i.e.: id="shopAllowed"...)
$(':radio').on('click', function (e) {
var row = $(this).closest('tr');
var checkBoxState = row.find('.checkBox').is(":checked");
if (checkBoxState == false) {
e.preventDefault();
}
});
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table shopListTable">
<tr>
<th>Shop Name</th>
<th>Allowed</th>
<th>Default</th>
</tr>
<tr>
<td>
name
</td>
<td>
<input class="checkBox" type="checkbox" id="shopAllowed1" name="shopAllowed" value="guid" />
guid
</td>
<td>
<input class="radioButton" type="radio" id="shopDefault2" name="shopDefault" value="guid" />
</td>
</tr>
<tr>
<td>
name
</td>
<td>
<input class="checkBox" type="checkbox" id="shopAllowed3" name="shopAllowed" value="guid" />
guid
</td>
<td>
<input class="radioButton" type="radio" id="shopDefault4" name="shopDefault" value="guid" />
</td>
</tr>
<tr>
<td>
name
</td>
<td>
<input class="checkBox" type="checkbox" id="shopAllowed5" name="shopAllowed" value="guid" />
guid
</td>
<td>
<input class="radioButton" type="radio" id="shopDefault6" name="shopDefault" value="guid" />
</td>
</tr>
</table>

Change CSS class declaration or actually apply style to every element?

I have a table with over 400 rows and about 90 columns. The visibility of the columns should be dynamic. I already assigned a css class .column(x) to every cell, where (x) is the column's index/count. Now i can change visibility in two ways:
$('.column5').css('display','block');
But that has to loop over 400 cells and possibly re-render the html on every iteration (?). The other method is:
$('.style').html().replace('.column5{display:none}','.column5{display:block}');
Where
<style class='style'>
.column1{display:none}
.column2{display:none}
.column3{display:none}
.column4{display:none}
.column5{display:none}
...
</style>
I'm using the first method now, but it's naturally quite slow with so many cells to change. The question is: could there be any performance gain from using the second method? Does it even make sense/is it a bad practice?
Thanks in advance!
I wouldn't do either. Instead, I'd have rules in the CSS like this:
.hide-column5 .column5 {
display: none;
}
...and then toggle the hide-column5 class on the container of the cells (e.g., the table or tbody as appropriate).
Example:
$("input[type=checkbox]").on("click", function() {
var cls = this.getAttribute("data-cls");
$("table").toggleClass(cls, !this.checked);
});
.hide-column1 .column1 {
display: none;
}
.hide-column2 .column2 {
display: none;
}
.hide-column3 .column3 {
display: none;
}
<table>
<thead>
<tr>
<th class="column1">Col 1</th>
<th class="column2">Col 2</th>
<th class="column3">Col 3</th>
</tr>
</thead>
<tbody>
<tr>
<td class="column1">1</td>
<td class="column2">2</td>
<td class="column3">3</td>
</tr>
<tr>
<td class="column1">1</td>
<td class="column2">2</td>
<td class="column3">3</td>
</tr>
<tr>
<td class="column1">1</td>
<td class="column2">2</td>
<td class="column3">3</td>
</tr>
</tbody>
</table>
<div>
<label>
<input checked type="checkbox" data-cls="hide-column1"> Show 1
</label>
</div>
<div>
<label>
<input checked type="checkbox" data-cls="hide-column2"> Show 2
</label>
</div>
<div>
<label>
<input checked type="checkbox" data-cls="hide-column3"> Show 3
</label>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Why does JQuery show() function only work on one (rather than all) of elements with the selector?

JSFiddle.
In the following SSCCE, there is a <table> nested inside another <table>.
The question is about the click listener for #add button. Specifically, the last if/else block of the function. When you run this code, click the Add TextField button once (or more times), and you will see that the #remove button on which show() should be executed, is only shown for the first matched selector, and not both (or all) of them.
Ideally the Remove TextField should be shown for all the #remove selectors.
The question is why? How do I fix this?
$(document).on("click", "button#add", function() {
event.preventDefault();
var parentTable = $(this).parent().parent().parent().parent().parent().parent().parent().parent();
var lastTableRow = parentTable.children('tbody').children('tr:last');
//Adding the new row
parentTable.children('tbody').append(lastTableRow.clone());
//Reset lastRow variable
lastTableRow = parentTable.children('tbody').children('tr:last');
//Reset the fields
lastTableRow.find('table tbody tr td input').each(function() {
$(this).val('');
});
//update numberOfRows variable
var numberOfRows = parentTable.children('tbody').children('tr').length;
alert("numberOfRows:" + numberOfRows); //check
if (!(numberOfRows > 1)) {
$("#remove").hide();
} else {
$("#remove").show();
}
});
#outer-table {
padding: 20px;
border: 3px solid pink;
}
#inner-table {
border: 3px solid orange;
}
#remove {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="outer-table">
<tbody>
<tr>
<td>
<table id="inner-table">
<tbody>
<tr>
<td>
<p style="display:inline-block">Enter first complain:</p>
<input type="text" />
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button id="add">Add Textfield</button>
<button id="remove">Remove Textfield</button>
</td>
</tr>
</tfoot>
</table>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Table Footer</td>
</tr>
</tfoot>
</table>
That's because you're using id for a group of objects. id should be unique per document. You should use a class name instead.

Check/uncheck a checkbox in the table row when any checkbox in the same row is clicked

I have a simple table as following which has checkboxes in the first and last columns of each row.
<table style="width:100%">
<tr>
<td><input type="checkbox" /></td>
<td>Smith</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td><input type="checkbox" /></td>
<td>Jackson</td>
<td><input type="checkbox" /></td>
</tr>
</table>
Problem:
When I check/uncheck the last column's checkbox in the first row, the first column's checkbox in the same row should be checked/unchecked. Similarly, if I check/uncheck the first column's checkbox, the corresponding last column checkbox should be checked/unchecked.
How can I achieve this in javascript? Any help or pointers would be really appreciated.
Here is the fiddle which I have created: Fiddle
Thank you.
Use :checkbox selector to select input type checkbox elements.
Try this:
$(':checkbox').on('change', function() {
$(this).closest('tr').find(':checkbox').prop('checked', this.checked);
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table style="width:100%">
<tr>
<td>
<input type="checkbox" />
</td>
<td>Smith</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Jackson</td>
<td>
<input type="checkbox" />
</td>
</tr>
</table>
Using JavaScript:
Use querySelectorAll('[type="checkbox"]') to find checkbox elements.
Try this:
var checkboxes = document.querySelectorAll('[type="checkbox"]');
[].forEach.call(checkboxes, function(checkbox) {
checkbox.onchange = function() {
var currentRow = this.parentNode.parentNode;
var cbElems = currentRow.querySelectorAll('[type="checkbox"]');
[].forEach.call(cbElems, function(cb) {
cb.checked = this.checked;
}.bind(this))
};
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<table style="width:100%">
<tr>
<td>
<input type="checkbox" />
</td>
<td>Smith</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Jackson</td>
<td>
<input type="checkbox" />
</td>
</tr>
</table>
One possible Javascript solution to toggle Checkboxes on Table Row click is shown below:
HTML
<table id = "Table1">
<tr>
<td><input type="checkbox" /></td>
<td>John Smith</td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td><input type="checkbox" /></td>
<td>Anna Warner</td>
<td><input type="checkbox" /></td>
</tr>
</table>
CSS
table, th, td{
border: 1px solid #c0c0c0;
border-collapse: collapse;
}
table{width:100%;}
Javascript
// row click will toggle checkboxes
row_OnClick("Table1")
function row_OnClick(tblId) {
try {
var rows = document.getElementById(tblId).rows;
for (i = 0; i < rows.length; i++) {
var _row = rows[i];
_row.onclick = null;
_row.onclick = function () {
return function () {selectRow(this);};
}(_row);
}
}
catch (err) { }
}
function selectRow(row) {
row.cells[0].firstChild.checked = !row.cells[0].firstChild.checked;
row.cells[2].firstChild.checked = row.cells[0].firstChild.checked;
}
Working jsfiddle demo at: https://jsfiddle.net/t6nsxgnz/
Practical implementation at: http://busny.net
You can further customize this solution pertinent to your task by modifying the selectRow(row) function:
function selectRow(row) {
row.cells[0].firstChild.checked = // add your code for the 1st CheckBox
row.cells[2].firstChild.checked = // add your code for the 2nd CheckBox
}
Another variation of this functionality coded in jQuery can be found in online pop-quiz engine (http://webinfocentral.com), implemented via the follwoing code snippet:
// toggle Checkboxes on row click
$(Table1 tr').click(function (event) {
// find the checkbox in the row
var _chk = $(this).find('input:checkbox');
if (!($(event.target).is("checkbox"))) {
$(_chk).prop('checked', !$(_chk).prop('checked'));
}
});
In this case, Row Click (at any place of the Row) or CheckBox Click events will toggle the state of that particular CheckBox. The state of other CheckBoxes can be synchronized with this one (by using "siblings" property, for example).
Hope this may help.

Categories