Issue
I have a table with checkbox in every row and filtering mechanism.
function toggle(source) {
checkboxes = document.getElementsByName('cbox');
for (var i = 0, n = checkboxes.length; i < n; i++) {
checkboxes[i].checked = source.checked;
}
}
function FilterTable() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("txtFilter");
filter = input.value.toUpperCase();
table = document.getElementById("tblEmployees");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[1];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<input type="text" id="txtFilter" onkeyup="FilterTable()" />
<table id="tblEmployees">
<thead>
<tr>
<th><input type="checkbox" onClick="toggle(this)"></th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 1</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 2</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 3</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>Mark 1</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>Mark 2</td>
</tr>
</tbody>
</table>
Currently, when I check the main checkboxes in the header, all checkbox in the table gets checked, even if the row is hidden when I filter the table. What I need to do is to check only the checkboxes that are not hidden.
For example, I filter "John". 3 rows will remain visible and the 2 "Mark" records will be hidden. Then, I tick the checkbox in the header, only the 3 "John" records should be checked. So when I clear the filter, the 2 "Mark" records remain unchecked.
Solution
Version 1: Minimal change on your code
You simply need to check for the style.display
of the parenting row in your function toggle
.
function toggle(source){
checkboxes = document.getElementsByName('cbox');
for(var i = 0, n = checkboxes.length; i < n; i++){
//REM: Fetch the closest <tr> element
const tTR = checkboxes[i].closest('tr');
//REM: Only change if not display "none"
if(tTR.style.display !== 'none'){
checkboxes[i].checked = source.checked
}
}
}
Version 2: Adding forEach
Instead of style.display
you could also make use of the hidden
property and instead of a for-loop
you could go for forEach
.
function toggle(source){
document.getElementsByName('cbox').forEach(checkbox => {
//REM: Only change if not display "none"
if(checkbox.closest('tr').style.display !== 'none'){
checkbox.checked = source.checked
}
})
}
Version 3: Use classes instead of styles
This is the way I would approach it, using classes instead of setting style
.
function toggle(source){
document.querySelectorAll('tr:not(.Hidden) [name=cbox]').forEach(checkbox => {
checkbox.checked = source.checked
})
};
function FilterTable(){
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("txtFilter");
filter = input.value.toUpperCase();
table = document.getElementById("tblEmployees");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++){
td = tr[i].getElementsByTagName("td")[1];
if (td){
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].classList.remove('Hidden')
} else {
tr[i].classList.add('Hidden')
}
}
}
};
.Hidden{
display: none
}
<input type="text" id="txtFilter" onkeyup="FilterTable()" />
<table id="tblEmployees">
<thead>
<tr>
<th><input type="checkbox" onClick="toggle(this)"></th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 1</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 2</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>John 3</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>Mark 1</td>
</tr>
<tr>
<td><input type="checkbox" name="cbox"/></td>
<td>Mark 2</td>
</tr>
</tbody>
</table>
Answered By - Lain
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.