How to not allow deleting all rows in table? - javascript

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);
});
});

Related

hide button in a row on certain value of a column

I have an autogenerated table with tasks and their status. Each row has a button to restart the task.
I want to hide the restart button if the the value of the task isn't equal to "Error". So in other words: only the tasks with Status==Error should have a visible restart button
here is a fiddle link: https://jsfiddle.net/hwqt7c3a/5/
I have tried:
window.onload = function () {
$(function () {
$('table tr').each(function () {
var Cells = this.getElementsByTagName("td");
if (Cells[2].innerText !== 'Error') {
$(this).find('button').style.visibility = 'hidden';
}
});
});
}
but for some reason Cells is always empty.
I have updated your fiddle , Here is the working fiddle
$(function() { //document ready event
$('table tr').each(function() { //loop all tr's
var Cell = $(this).find('td:eq(2)'); //find the 3rd td cell
if (Cell.text() !== 'Error') { //check if its text is "Error"
$(this).find('button').hide(); //if try then find the button of this tr and hide it
}
});
});
Do not mix javascript and Jquery syntax,
Also you don't need both these lines
window.onload = function () { // javascript way of handling document ready
$(function () { // jquery way of handling document ready.
use either one, Since you are using Jquery library then its better you use
$(function () {
So that you dont mix up the syntaxes..
if you want the td to take up the button space in the UI but still be hidden then you have use
$(this).find('button').css("visibility","none")
;(function($){
$(document).ready(function(){
$('table tr').each(function () {
if ($(this).find("td").eq(2).text() !== 'Error') {
$(this).find('button').css("visibility","none")
}
});
})
})(jQuery)
P.s: you already use jQuery so i would recommend to not mix it with vanilla js. Try this.
You can use the :nth-child selector to check is the value is === Error and then go to the first child and remove the button with empty() function
Code:
$(document).ready(function() {
$('table tr').each(function() {
if($(this).children(':nth-child(3)').text() === 'Error'){
$(this).children(':nth-child(1)').empty();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border='1'>
<thead>
<th></th>
<th>ID</th>
<th>Status</th>
</thead>
<tbody>
<tr class="grid-row ">
<td class="grid-cell" data-name="">
<button type="submit">Restart</button>
</td>
<td class="grid-cell" data-name="job_id">2349</td>
<td class="grid-cell" data-name="JobStatusName">Completed</td>
</tr>
<tr class="grid-row ">
<td class="grid-cell" data-name="">
<button type="submit">Restart</button>
</td>
<td class="grid-cell" data-name="job_id">6585</td>
<td class="grid-cell" data-name="JobStatusName">Error</td>
</tr>
<tr class="grid-row ">
<td class="grid-cell" data-name="">
<button type="submit">Restart</button>
</td>
<td class="grid-cell" data-name="job_id">4564</td>
<td class="grid-cell" data-name="JobStatusName">Processing</td>
</tr>
</tbody>
</table>
Change script as per below. It have some minor change in your script for error handling.
<script>
window.onload = function () {
$(function () {
$('table tr').each(function () {
var Cells = this.getElementsByTagName("td");
if (Cells != undefined && Cells.length > 0 && Cells[2].innerText !== 'Error') {
$(this).find('button').attr("style", "visibility: hidden");
}
});
});
}
</script>
Check this Fiddle
You don't need to mix window.onLoad() with jquery
and there is argument for $.each(function(i, e){}); which gives you the iterating html element
EDIT:
$(function() {
$('table tbody tr').each(function(i, e) {
var status = $(e).find("td:eq(2)").html();
if (status !== 'Error') {
$(e).find('button').hide();
}
});
});

using jquery to highlight either tr's or td's

I have two tables:
<table class="highlight_row" id="table1">
<tr id="first_row">
<td><input type="checkbox" id="first">first thing</td>
<td><input type="checkbox" id="second">second thing</td>
<td><input type="checkbox" id="third">third thing</td>
</tr>
</table>
<table class="highlight_td" id="table2">
<tr id="second_row">
<td><input type="checkbox" id="fourth">fourth thing</td>
<td><input type="checkbox" id="fifth">fifth thing</td>
<td><input type="checkbox" id="sixth">sixth thing</td>
</tr>
</table>
and I am trying to differenciate them -- when I check any box in the first table, I want that whole row to be highlighted, and when I check a box in the second table, I want just that td to be highlighted.
I am able to get rows highlighted (using addClass() to a 'selected' color), but when I specify the table class, I still get the whole row for the second table, when I just want the td (I figure identifying by class instead of id will be better in the long run as I add more tables).
jquery code:
$(".highlight_row").click(function(){
$(":checkbox").change(function() {
$(this).closest("tr").toggleClass("selected", this.checked)
})
});
Something like this fiddle, perhaps?
Your HTML.
CSS:
.highlight { background: #ff0; }
JS:
$("#table1 input[type=checkbox]").on('click', function ()
{
$(this).parent().parent().toggleClass('highlight');
});
$("#table2 input[type=checkbox]").on('click', function ()
{
$(this).parent().toggleClass('highlight');
});
For the first table, you'll want to eval all of the checkboxes so it doesn't get un-highlighted. The second table is much easier.
Fiddle: http://jsfiddle.net/24vm61dk/
$(function () {
// Highlight Row
$('#table1 input[type="checkbox"]').on('change', function () {
var anyChecked = false;
$(this).closest('tr').find('input[type="checkbox"]').each(function () {
if ($(this).prop('checked')) {
anyChecked = true;
}
});
if (anyChecked) {
$(this).closest('tr').addClass('highlight');
} else {
$(this).closest('tr').removeClass('highlight');
}
});
// Highlight Cell
$('#table2 input[type="checkbox"]').on('change', function () {
var checked = $(this).prop('checked');
if (checked) {
$(this).closest('td').addClass('highlight');
} else {
$(this).closest('td').removeClass('highlight');
}
});
});
Code shown is adding change handler within a click handler on the whole table.
This will lead to compounding events and can lead to serious browser performance problems if user clicks a lot in table.
Simply put, click on table 4 times and every time a checkbox gets changed it will trigger 4 change handlers
A simple way for the row highlighting would be to use the count of checked checkboxes in the row to determine the class state
$('table.highlight_row input:checkbox').change(function(){
var $row = $(this).closest('tr'),
hasChecked = $row.find(':checkbox:checked').length;
$row.toggleClass('selected', hasChecked);
});
The cell highlighting is even easier...just toggle the class on the parent cell based on the checked state
$('table.highlight_td input:checkbox').change(function(){
$(this).parent().toggleClass('selected', this.checked);
});
For rows use:
.highlight_row .selected {
background: yellow;
}
for the cell use:
.highlight_td .selected td:nth-child(1) {
background: yellow;
}

Unmark checkbox when there is no more TR and TABLE goes hide

I'm working on this function for remove any marked checkbox in a selector container element. The code works fine but has a small problem: I'm not able to uncheck the first checkbox (the one that toggle all the checkboxes in a selector2 container). Now this is the code for remove the checked checkboxes:
function eliminarMarcados(selector, toggleMsg, msgSelector) {
$(selector + " input[type='checkbox']:checked").closest("tr").not('.tableHead').remove();
if (toggleMsg) {
if ($(selector + " tbody tr").length == 0) {
$(msgSelector).show();
$(selector).hide();
// 1st test didn't work since it's not right
//$(selector + " tr").hasClass('tableHead').$(selector + " input[type='checkbox']").prop('checked', false);
}
}
}
And this is how I call it:
$("#btnEliminarNorma").on('click', function () {
eliminarMarcados("#tablaNorma", true, "#alertSinNorma");
});
This is the code I'm using for toggle all checkboxes checked:
function marcarTodosCheck(selChk, tableBody) {
$(selChk).on('click', function () {
var $toggle = $(this).is(':checked');
$(tableBody).find("input:checkbox").prop("checked", $toggle).trigger("change");
});
$(tableBody).find("input:checkbox").on('click', function () {
if (!$(this).is(':checked')) {
$(selChk).prop("checked", false).trigger("change");
} else if ($(tableBody).find("input:checkbox").length == $(tableBody).find("input:checkbox:checked").length) {
$(selChk).prop("checked", true).trigger("change");
}
});
}
And I call it as follow:
marcarTodosCheck("#toggleCheckNorma", "#tablaNorma");
And this is the HTML code behind this:
<table class="table table-condensed" id="tablaNorma">
<thead>
<tr class="tableHead">
<th><input type="checkbox" id="toggleCheckNorma" name="toggleCheckNorma"></th>
<th>Nro.</th>
<th>Norma COVENIN</th>
<th>Año de Publicación</th>
<th>Comité Técnico</th>
</tr>
</thead>
<tbody id="normaBody">
<tr class="">
<td><input type="checkbox" value="5"></td>
<td>382</td><td>Sit alias sit.</td>
<td>1970</td><td>Velit eum.</td>
</tr>
<tr class="">
<td><input type="checkbox" value="6"></td>
<td>38362</td>
<td>Et voluptatem.</td><td>1976</td>
<td>Et voluptatem.</td>
</tr>
</tbody>
</table>
How I can unmark the first checkbox?
I've just made a Fiddle with an additional <button id="btnEliminarNorma">Uncheck</button> to remove the checkmarks and the adjustment of your first approach in the function eliminarMarcados() :
$(selector).find(" input[type='checkbox']").prop('checked', false);

jQuery checkbox triggering the checking of other checkboxes

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.

Select data attribute from row only for rows with checked checkboxes

I have table has 2 columns: checkbox and name.
<table id="data">
<tr class="header">
<th>
<input type="checkbox" class="download" />
</th>
<th>Name</th>
</tr>
<tr data-id="1">
<td>
<input type="checkbox" class="download" />
</td>
<td>One</td>
</tr>
<tr data-id="2">
<td>
<input type="checkbox" class="download" />
</td>
<td>Two</td>
</tr>
<tr data-id="3">
<td>
<input type="checkbox" class="download" />
</td>
<td>Something</td>
</tr>
</table>
I would like to select data attribute from those rows that have checkbox selected. Right now I'm doing it this way:
$(document).on('click', "#select", function (e) {
var mydata=[];
$.each($('#data tbody tr:not(.header)'), function(i, row) {
if($(row).find('input[type=checkbox]').is(":checked"))
mydata.push($(row).data('id'));
});
console.log(mydata);
});
This works fine, but can this be done better/faster?
Here is my working demo: http://jsfiddle.net/Misiu/yytR2/2/
Also how can I uncheck checkbox in header when one of more checkboxes in body are unchecked and check it when all will get checked?
EDIT: My final working code (thanks to #tymeJV):
$(document).on('change', "#data tr.header input.download", function (e) {
$('#data tbody tr:not(.header) input.download').prop('checked', $(this).is(":checked"));
});
$(document).on('change', "#data tr:not(.header) input.download", function (e) {
if ($(this).is(":checked") && $('#data tr:not(.header) input.download:not(:checked)').length == 0) {
$('#data tbody tr.header input.download').prop('checked', true);
} else {
$('#data tbody tr.header input.download').prop('checked', false);
}
});
$(document).on('click', "#select", function (e) {
var rows = $("#data tr:not(.header) td input:checked").map(function () {
return $(this).closest("tr").data("id");
}).get();
console.log(rows);
});
You can do:
var rows = $("#data tr:not(.header) td input:checked").map(function() {
return $(this).closest("tr").data("id");
}).get();
It iterates yet, but only checked rows.
You can use:
$(".download:checkbox").map(function() {
return $(this).parents('tr').data('id');
}).get()

Categories