Home > OS >  Check all checkboxes in a table which row is not hidden
Check all checkboxes in a table which row is not hidden

Time:10-19

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.

CodePudding user response:

You want to check if the table-row is hidden before you check the box.

So, within your for loop I've added an if statement which searches for the closest('tr'), and checks if it's hidden or not.

function toggle(source) {
  checkboxes = document.getElementsByName('cbox');
  for (var i = 0, n = checkboxes.length; i < n; i  ) {
    if(checkboxes[i].closest('tr').style.display != "none") {
      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>

CodePudding user response:

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

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

CodePudding user response:

There's several ways to do this but a simple way to solve it would be to add a data attribute to your hidden rows and then check for that in your filter function.

I'd recommend doing this over checking for a style property to avoid coupling your script too closely to the particulars of how something is styled.

function toggle(source) {
            var checkboxes = document.getElementsByName('cbox');
            var tr = document.querySelectorAll("tbody tr");
            for (var i = 0, n = checkboxes.length; i < n; i  ) {
                if(tr[i].dataset.hidden === "true"){
                  continue;
                 }
                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].dataset.hidden = "false";
                        tr[i].style.display = "";
                    } else {
                        tr[i].dataset.hidden = "true";
                        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>

You could also do the same more directly with a 'hidden' attribute, and avoid the redundancy of having both a 'style' and a data attribute.

  • Related