jQuery checkbox triggering the checking of other checkboxes - javascript

I have a table which has a header row containing a checkbox and also has checkboxes in each of the body rows.
When the user checks the header checkbox, each of the body checkboxes also gets checked, and if one of these body checkboxes is unchecked the header checkbox gets unchecked. This is working fine, but I now want to add more tables which are linked to each of the body rows on the first table.
Here's an example of the html:
<table class="parent-table">
<thead>
<tr>
<th>Title</th>
<th>
<input type="checkbox" />
</th>
</tr>
</thead>
<tbody>
<tr data-user-id="ID1">
<td>ID1</td>
<td>
<input type="checkbox" />
</td>
</tr>
</tbody>
</table>
<br /><br />
<table class="child-table" id="ID1">
<thead>
<tr>
<th>ID1</th>
<th>
<input type="checkbox" />
</th>
</tr>
</thead>
<tbody>
<tr>
<td>One</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>Two</td>
<td>
<input type="checkbox" />
</td>
</tr>
<tr>
<td>Three</td>
<td>
<input type="checkbox" />
</td>
</tr>
</tbody>
</table>
So now I have a child table which works the same way as the original table but I would also like the checkbox from the row in the parent table to work the same way as the header checkbox in the child table, so when all the checkboxes are checked in the child table, the header checkbox and the checkbox from the row in the parent table get checked.
To add a further level of complexity, I would ultimately like to use indeterminate states on the checkboxes if 'some' of the checkboxes are checked.
Here's the javascript/jQuery I have so far... I think the main thing that's not working is when the checkbox from the parent table gets automatically checked, the header checkbox from that parent table is not being checked if all rows are checked.
/* SEPARATE FROM THE OTHER 'ON CHANGE' CODE BECAUSE THIS IS USED ON ALL TABLES */
$(document).on('change', 'td input[type=checkbox]', function () {
var ind = $(this).closest("td").index();
check_checkbox($(this).closest('table'), ind);
});
$('table th input[type=checkbox]').click(function () {
var checked = $(this).prop('checked');
var ind = $(this).closest("th").index();
$(this).closest('table').find('tbody tr').each(function () {
$(this).find('td:eq(' + ind + ') input[type=checkbox]:not(:disabled)').prop('indeterminate',false).prop('checked', checked).trigger('change');
});
});
function check_checkbox(table, pos) {
if (!pos) pos = 0;
var count = 0;
var checked = 0;
table.find("tbody tr").each(function () {
count = count + $(this).find('td:eq(' + pos + ') input[type=checkbox]:not(:disabled)').length;
checked = checked + $(this).find('td:eq(' + pos + ') input[type=checkbox]:checked').length;
});
table.find('th:eq(' + pos + ') input[type=checkbox]').prop('checked', count == checked && count > 0).prop('indeterminate',false).trigger('change');
}
/* *********************** */
$(document).on('change', '.parent-table td input[type=checkbox]', function() {
var checkit = $(this).prop('checked');
var a = $(this).closest('tr').attr('data-user-id');
$("table#"+a).find("tr").each( function() {
$(this).find("input[type=checkbox]").prop("checked", checkit);
});
});
$(document).on('change', '.child-table td input[type=checkbox]', function() {
var a = $(this).closest('table').attr('id');
var b = $(this).closest("tbody").find("input[type=checkbox]").length;
var c = $(this).closest("tbody").find("input[type=checkbox]:checked").length;
if(b == c) {
$("table tr[data-user-id="+a+"]").find("input[type=checkbox]").prop("checked", true).prop('indeterminate',false);
} else if(c == 0) {
$("table tr[data-user-id="+a+"]").find("input[type=checkbox]").prop("checked", false).prop('indeterminate',false);
} else {
$("table tr[data-user-id="+a+"]").find("input[type=checkbox]").prop("checked", true).prop('indeterminate',true);
}
});
And here's a jsfiddle... http://jsfiddle.net/5cBTT/

The problem is that in your check_checkbox() function, you are only updating header chkbox of the targeted table. For example, if you check all the boxes from the child table, you are updating the header boxe of this table but not the main one. What you should do is, in your
$(document).on('change', '.child-table td input[type=checkbox]', function() {
Add
check_checkbox($(".parent-table"),$(this).closest("td").index());
behind each
...").prop("checked", ...
here's a working fiddle
http://jsfiddle.net/TCHdevlp/5cBTT/1/
Also, I recommend you to bind checkboxes with the onchange event instead of counting checked boxes against boxes count. If one day, you want to use pagination in your tables, the count will only count visible checkboxes. So, if you check the "check all" box, only boxes of the current page will be checked. Also, each time your are checking a box, your are re-counting all the boxes of your page, wich can be a big number.

Related

How to select all boxes using input type checkbox

picture of my columns and checboxes
<table class="table table-striped grid-table">
<tr>
<th>Id</th>
<th>Code</th>
<th>
<input type="checkbox" id="box"/>
</th>
</tr>
#foreach (var item in (IEnumerable<cit.Models.getPersonPerName_Result>)Model)
{
<tr>
<td>#item.idper</td>
<td>#item.pername</td>
<td>
<div class="pure-checkbox">
<input type="checkbox" id="#item.idper" class="chk" checked="#(item.idperson == ViewBag.idperson ? true : false)" name="#item.id.ToString()" id="#item.id.ToString()" />
<label for="#item.id.ToString()"></label>
</div>
</td>
</tr>
}
I have defined class pure-checkbox, so item.idper is my column with values of my document, and item.pername is my column with codes of my document, and there is pure-checkbox column which I defined for checkboxes which i can check only one by one, but i want to check them all using input type on the code above.
The way to to this is to listen for changes in the state of the 'master' checkbox. You can do this by attaching an event handler. When this handler is triggered you have to set the checked state of all other checkboxes to the checked state of the 'master' checkbox:
var selectAllBox = document.getElementById('box');
selectAllBox.addEventListener('click', function() {
var pureCheckboxes = document.getElementsByClassName('chk');
for(var i = 0; i < pureCheckboxes.length; i++) {
pureCheckboxes[i].checked = this.checked;
}
});
A working JSFiddle: https://jsfiddle.net/TDucheyne/raxdzw1f/
You can do it with a single line as
$(document).ready(function(){
$("#box").change(function(){
$(".chk").prop('checked',$(this).prop('checked'));
});
});
JSFiddle

How to not allow deleting all rows in table?

I have a simple table with 3 columns with classes = "code","description","delete" the column has class "delete" is a checkbox type, and one button with class="savebtn".
I need the following :
When user click save :
the Jquery must verify the code column that it has data.
If any cell in delete column is checked, Delete that row.
If the user checked all cells in delete column alert message that the table must has at least one row , and don't delete the rows.
this is a Demo but it not working with me.
that what i tried :
$(document).ready(function (){
$(".savebtn").bind("click", function(e){
$('.savebtn').attr('disabled',true);
$('.table tbody tr').each(function () {
$(this).find('.code input').each(function () {
if ($(this).closest("tr").find(".delete input").is(":checked") && $('.cf-table-block tbody tr').length >=1){
$('.delete input :checkbox:checked').closest('tr').remove();
$('.savebtn').removeAttr('disabled');
}else if($(this).closest("tr").find(".delete input").is(":checked") && $('.cf-table-block tbody tr').length <2){
e.preventDefault();
}else if($('.delete input').prop('checked')==false && ( $(this).val().length>0)){
$('.savebtn').removeAttr('disabled');
}else if ($('.delete input').prop('checked')==false && ( $(this).val().length==0)){
$(this).attr("placeholder", "Please fill this field");
}
});
});
});
});
First, you should look at wrapping your table header in <thead> and body in <tbody>. This will allow you to determine how many rows are relevant to our needs.
It'd be good to then create an array of rows that are checked to be deleted, this can then be compared (via length) to the original amount of rows.
Here's an example - I've removed a lot of the logic as the use of an array to store checked rows will help remove the need for a lot of those conditionals.
Here's a fiddle.
Edit: Here's a new fiddle in which i've added a button for you to clear/populate the last rows value so you can test.
This is updated fiddle of what you are trying to do.
https://jsfiddle.net/ko55Lbt3/6/
$(document).ready(function (){
$(".savebtn").bind("click", function(e){
$('.savebtn').attr('disabled',true);
if($(".table tr [type='checkbox']:checked").length >= $('.table tr').length -1)
{
alert("all rows can not be deleted");
return false;
}
$('.table tr').each(function () {
$(this).find('.code input').each(function () {
if ($(this).closest("tr").find(".delete input").is(":checked")){
if($(this).val().length > 0)
{
$(this).closest("tr").remove();
$('.savebtn').removeAttr('disabled');
}
else
{
$(this).attr("placeholder", "Please fill this field");
}
}
});
});
});
});
There are few problem with selectors in your current code which i have corrected.For example "tbody" element is no where, the td should not have the type attribute.
I've done it with a simple count on each click:
See in Fiddle
$(document).ready(function (){
// on click "Save"
$(".savebtn").bind("click", function(e){
$('.savebtn').attr('disabled',true);
// Delete rows
$("input:checkbox").each(function () {
if($(this).prop("checked")){
$(this).closest("tr").remove();
}
});
});
// on click a checkbox
$("input:checkbox").on("click", function(){
checkboxCount=0;
$("input:checkbox").each(function(){
checkboxCount++;
});
$("input:checkbox").each(function(){
if($(this).prop("checked")){
checkboxCount--;
}
});
// this is just to see the value in jsFiddle
$("#console").html(checkboxCount);
// If there is no checkbox unchecked, disables the Save button and alert.
if(checkboxCount<1){
alert("Table must have at least one row!");
$('.savebtn').attr('disabled',true);
}else{
$('.savebtn').attr('disabled',false);
}
});
});
Try this one:
https://jsfiddle.net/ersamrow/f7ce7dpj/
HTML:
<table class="table" style="width:100%" border="1">
<thead>
<tr>
<th class="code">Code</th>
<th class="description">Description</th>
<th class="delete">Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td class="code" type="text">1</td>
<td type="text">aa</td>
<td class="delete">
<input type="checkbox">
</td>
</tr>
<tr>
<td class="code" type="text">2</td>
<td type="text">bb</td>
<td class="delete">
<input type="checkbox">
</td>
</tr>
<tr>
<td class="code" type="text">3</td>
<td type="text">cc</td>
<td class="delete">
<input type="checkbox">
</td>
</tr>
</tbody>
</table>
<br>
<input class="savebtn" style="width: 65px; font-size: 16px;" type="button" value="Save">
Script:
$(document).ready(function() {
// on click "Save"
$(".savebtn").bind("click", function(e) {
$('.savebtn').attr('disabled', true);
var table_rows = $('table tbody').find('tr').length;
var checked = $('input:checkbox:checked').length;
if (checked < table_rows) {
// Delete rows
$("input:checkbox").each(function() {
if ($(this).prop("checked")) {
$(this).closest("tr").remove();
}
});
} else {
alert("Table must have at least one row!");
}
$('.savebtn').attr('disabled', false);
});
});

Select / deselect check boxes not working as expected using .closest('table').find('tbody > tr')

I have following simple table and managed to select / deselect all check boxes by clicking on the check box in the head of the table.
Also: when I click on th check box, all other check boxes are selected and when I click the th check box once again, all other check boxes are deselected.
The problem is so: when all check boxes are selected and I click in one of those other check boxes, it is deselected, but the th check box should be automatic deselect as well, what doesn't occur.
And on the other side, when 2 of the check boxes are selected and I click on the last one, the th check box should be also selected, what doesn't occur as well.
Does anybody has an idea how I could manage to do this in this specific code?
Here the javascript:
// Select / deselect check boxes on free text search page.
jQuery(function($) {
// Select / deselect all rows according to table header checkbox.
var active_class = 'active';
$('#simple-table > thead > tr > th input[type=checkbox]').eq(0).on('click', function(){
var th_checked = this.checked; // Checkbox inside "TH" table header.
$(this).closest('table').find('tbody > tr').each(function(){
var row = this;
if(th_checked) $(row).addClass(active_class).find('input[type=checkbox]').eq(0).prop('checked', true);
else $(row).removeClass(active_class).find('input[type=checkbox]').eq(0).prop('checked', false);
});
});
// Select / deselect a row when the checkbox is checked / unchecked.
$('#simple-table').on('click', 'td input[type=checkbox]' , function(){
var $row = $(this).closest('tr');
if(this.checked) $row.addClass(active_class);
else $row.removeClass(active_class);
});
});
and here the html:
<table id="simple-table" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th class="center">
<label class="pos-rel">
<input class="ace" type="checkbox" />
<span class="lbl"></span>
</label>
</th>
<th>Areas:</th>
</tr>
</thead>
<tbody>
<tr>
<td class="center">
<label class="pos-rel">
<input class="ace" name="ma1" type="checkbox" value="1" checked="" />
<span class="lbl"></span>
</label>
</td>
<td>
<span>Option 01</span>
</td>
</tr>
<tr>
<td class="center">
<label class="pos-rel">
<input class="ace" name="ma2" type="checkbox" value="1" />
<span class="lbl"></span>
</label>
</td>
<td>
<span>Option 02</span>
</td>
</tr>
<tr>
<td class="center">
<label class="pos-rel">
<input class="ace" name="ma3" type="checkbox" value="1" />
<span class="lbl"></span>
</label>
</td>
<td>
<span>Option 03</span>
</td>
</tr>
</tbody>
</table>
I've tried upon others to add following code, but nothing has worked:
var tr_checked = this.checked; // Checkboxes checked.
$(this).closest('table').find('tbody > tr').each(function(){
var row = this;
if(tr_checked) $(row).addClass(active_class).find('input[type=checkbox]').eq(0).prop('checked', true);
else $(row).removeClass(active_class).find('input[type=checkbox]').eq(0).prop('checked', false);
});
I would appreciate if you could help me using this approach to make it work.
I would do it this way.
var $thead = $('#simple-table thead');
var $tbody = $('#simple-table tbody');
// Event handler for the .ace checkbox inside <thead>.
$thead.find('.ace').change(function() {
if ($(this).prop("checked")) {
$tbody.find('.ace').prop("checked", true);
} else {
$tbody.find('.ace').prop("checked", false);
}
});
// Event handler for .ace checkboxes inside <tbody>.
$tbody.on("change", ".ace", function() {
if ($tbody.find('.ace:checked').length == $tbody.find('.ace').length) {
$thead.find('.ace').prop("checked", true);
} else {
$thead.find('.ace').prop("checked", false);
}
});
JSFiddle
Your code appears to be working, at least in chrome. Here is a jsfiddle
If you want the master checkbox to work as expected i changed the fiddle with an working example
if(this.checked) {
$row.addClass(active_class);
//check if all checkboxes are checked
if(table.find("tbody input[type=checkbox]:not(:checked)").length ==0){
headerCheckbox.prop('checked', true);
}
} else {
$row.removeClass(active_class);
headerCheckbox.prop('checked', false);
}

javascript validation of dynamic checkbox

Name and id of checkboxes are appearing dynamically. And we are not sure of number of checkboxes. A map is iterated to generate checkboxes contained in a table. So, each table will have a checkbox with 2-3 options depending on map entries. Javascript should validate that at least one entry of checkbox in a table should be checked.
HashMap<ServerGroup, ArrayList<String>> serversMap = (HashMap<ServerGroup, ArrayList<String>>) session.getAttribute("userServersMap");
Iterator itr = serversMap.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry<ServerGroup, ArrayList<String>> entry = (Map.Entry<ServerGroup, ArrayList<String>>)itr.next();
<table border='1' align="center">
<tr>
<th>Select Server</th>
<th>Servers</th>
</tr>
<%
for (String server : entry.getValue()) {
%>
<tr>
<td><input type="checkbox" name="<%= entry.getKey().getName().toString() %>" value="<%=server%>"></td>
<td><%=server%></td>
</tr>
<%
}
%>
</table>
Try this with JS:
function checkOneCheckbox(){
var checkboxes=document.getElementsByName("your_checkbox_name"); //all should be same
var is_checked=false;
for(var i=0;i<checkboxes.length;i++)
{
if(checkboxs[i].checked)
{
is_checked=true;
}
}
if(is_checked){
//at least one is checked;
}else {
//...
}
}
More easy with jQuery:
// onready method...binding
var is_checked = false;
$('input[type="checkbox"]').each(function() {
if ($(this).is(":checked")) {
is_checked = true;
}
});
The following solution should hopefully work in this case.
Let's assume that your JSP generated the following html page
(say two html tables, it can generate any number of tables though for your case):
<table border='1' align="center">
<tr>
<th>Select Server</th>
<th>Servers</th>
</tr>
<tr>
<td><input type="checkbox" name="serverX" value="TestServer1"></td>
<td>TestServer1</td>
</tr>
<tr>
<td><input type="checkbox" name="serverY" value="TestServer2"></td>
<td>TestServer2</td>
</tr>
</table>
<table border='1' align="center">
<tr>
<th>Select Server</th>
<th>Servers</th>
</tr>
<tr>
<td><input type="checkbox" name="serverM" value="TestServer3"></td>
<td>TestServer3</td>
</tr>
<tr>
<td><input type="checkbox" name="serverN" value="TestServer4"></td>
<td>TestServer4</td>
</tr>
<tr>
<td><input type="checkbox" name="serverO" value="TestServer5"></td>
<td>TestServer5</td>
</tr>
</table>
Then on form submit you can call a Validate function which will iterate through all the tables on your page and if it finds a table without any checked checkbox it will return false and simply focus on the first checkbox of the table.
The Validate function will be :
function Validate()
{
var table = document.getElementsByTagName('table'); // get all the tables on the page
for(var i=0; i<table.length;i++) //loop through each table
{
var flag = false;
for( var j=1; j<table[i].rows.length;j++) // start checking from 2nd row of the table
{
var currentRow = table[i].rows[j];
var cell = currentRow.cells[0];
var elem = cell.getElementsByTagName("input");
if (elem[0].type == "checkbox")
{
if(elem[0].checked)
{
flag=true;
break; // stop checking this table as one checked found
}
}
}
if(j==table[i].rows.length && flag == false)
{
alert("Please select at least one checkbox!");
table[i].rows[1].cells[0].getElementsByTagName("input")[0].focus();//focus on the first checkbox in the table
return false;
}
}
}
Hope it helps!
Working Demo:
http://jsfiddle.net/6cyf4skd/

How can I get the corresponding table column (td) from a table header (th)?

I want to get the entire column of a table header.
For example, I want to select the table header "Address" to hide the address column, and select the "Phone" header to show the correspondent column.
<table>
<thead>
<tr>
<th id="name">Name</th>
<th id="address">Address</th>
<th id="address" class='hidden'>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td>Freddy</td>
<td>Nightmare Street</td>
<td class='hidden'>123</td>
</tr>
<tr>
<td>Luis</td>
<td>Lost Street</td>
<td class='hidden'>3456</td>
</tr>
</tbody>
I want to do something like http://www.google.com/finance?q=apl (see the related companies table) (click the "add or remove columns" link)
Something like this would work -
$('th').click(function() {
var index = $(this).index()+1;
$('table td:nth-child(' + index + '),table th:nth-child(' + index + ')').hide()
});
The code above will hide the relevant column if you click on the header, the logic could be changed to suit your requirements though.
Demo - http://jsfiddle.net/LUDWQ/
With a couple simple modifications to your HTML, I'd do something like the following (framework-less JS):
HTML:
<input class="chk" type="checkbox" checked="checked" data-index="0">Name</input>
<input class="chk" type="checkbox" checked="checked" data-index="1">Address</input>
<input class="chk" type="checkbox" checked="checked" data-index="2">Phone</input>
<table id="tbl">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>Freddy</td>
<td>Nightmare Street</td>
<td>123</td>
</tr>
<tr>
<td>Luis</td>
<td>Lost Street</td>
<td>3456</td>
</tr>
</tbody>
Javascript:
var cb = document.getElementsByClassName("chk");
var cbsz = cb.length;
for(var n = 0; n < cbsz ; ++n) {
cb[n].onclick = function(e) {
var idx = e.target.getAttribute("data-index");
toggleColumn(idx);
}
}
function toggleColumn(idx) {
var tbl = document.getElementById("tbl");
var rows = tbl.getElementsByTagName("tr");
var sz = rows.length;
for(var n = 0; n < sz; ++n) {
var el = n == 0 ? rows[n].getElementsByTagName("th")[idx] : rows[n].getElementsByTagName("td")[idx];
el.style.display = el.style.display === "none" ? "table-cell" : "none";
}
}
http://jsfiddle.net/dbrecht/YqUNz/1/
I added the checkboxes as it doesn't make sense to bind the click to the column headers as you won't be able to toggle the visibility, only hide them.
You can do something with CSS, like:
<html>
<head>
<style>
.c1 .c1, .c2 .c2, .c3 .c3{
display:none;
}
</style>
</head>
<body>
<table class="c2 c3">
<thead>
<tr>
<th id="name" class="c1">Name</th>
<th id="address" class="c2">Address</th>
<th id="phone" class="c3">Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td class="c1">Freddy</td>
<td class="c2">Nightmare Street</td>
<td class="c3">123</td>
</tr>
<tr>
<td class="c1">Luis</td>
<td class="c2">Lost Street</td>
<td class="c3">3456</td>
</tr>
</tbody>
</table>
</body>
</html>
To hide a column, you add with Javascript the corresponding class to the table. Here c2 and c3 are hidden.
You could add dynamically the .c1, .c2,... in a style tag, or define a maximum number.
The easiest way to do this would be to add a class to each td that matches the class of the header. When you click the , it checks the class, then hides every td with that class. Since only the s in that column would hide that class, it would effectively hide the column.
<table>
<thead>
<th>Name</th>
<th>Address</th>
</thead>
<tbody>
<tr>
<td class="Name">Joe</td>
<td class="Address">123 Main St.
</tbody>
</table>
And the script something like:
$('th').click( function() {
var col = $(this).html(); // Get the content of the <th>
$('.'+col).hide(); // Hide everything with a class that matches the col value.
});
Something like that, anyway. That's probably more verbose than it needs to be, but it should demonstrate the principle.
Another way would be to simply count how many columns over the in question is, and then loop through each row and hide the td that is also that many columns over. For instance, if you want to hide the Address column and it is column #3 (index 2), then you would loop through each row and hide the third (index 2).
Good luck..
Simulating the Google Finance show/hide columns functionality:
http://jsfiddle.net/b9chris/HvA4s/
$('#edit').click(function() {
var headers = $('#table th').map(function() {
var th = $(this);
return {
text: th.text(),
shown: th.css('display') != 'none'
};
});
var h = ['<div id=tableEditor><button id=done>Done</button><table><thead><tr>'];
$.each(headers, function() {
h.push('<th><input type=checkbox',
(this.shown ? ' checked ' : ' '),
'/> ',
this.text,
'</th>');
});
h.push('</tr></thead></table></div>');
$('body').append(h.join(''));
$('#done').click(function() {
var showHeaders = $('#tableEditor input').map(function() { return this.checked; });
$.each(showHeaders, function(i, show) {
var cssIndex = i + 1;
var tags = $('#table th:nth-child(' + cssIndex + '), #table td:nth-child(' + cssIndex + ')');
if (show)
tags.show();
else
tags.hide();
});
$('#tableEditor').remove();
return false;
});
return false;
});
jQuery('thead td').click( function () {
var th_index = jQuery(this).index();
jQuery('#my_table tbody tr').each(
function(index) {
jQuery(this).children('td:eq(' + th_index + ');').each(
function(index) {
// do stuff here
}
);
}
);
});
here's a working fiddle of this behaviour:
http://jsfiddle.net/tycRW/
of course, hiding the column with out hiding the header for it will have some strange results.

Categories