dcoop
dcoop

Reputation: 13

Toggle Visibility of HTML Table Rows Based on Checkbox Values

I have found a great number of questions and answers regarding showing/hiding rows in a table based on checkboxes, but have failed to find an answer that I can get to work for my scenario.

My problem - I have an HTML table where each row has a checkbox that the user can flag if they find that row important. I would like to have a "master" checkbox that toggles the behavior of the table - if master is checked then only show the checked rows on the table, if master is unchecked then show all rows of the table. I need to accomplish this with pure JS, no JQuery.

Any help is greatly appreciated!

Here is some sample HTML code I've been using as a test...

<span class="text-default">
  <input type="checkbox" class="down-checkbox" id="down" />
  <label for="down">Check to show Flags only</label>
</span>
<table class="table1">
  <thead>
    <tr>
      <th>Flag</th>
      <th>No.</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">ONE</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">TWO</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">THREE</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">FOUR</span></td>
    </tr>
  </tbody>
</table>

Upvotes: 1

Views: 940

Answers (4)

zer00ne
zer00ne

Reputation: 43920

Instead of input.parentElement.parentElement to get ancestor <tr> try input.closest('tr') it's less bulkier and easier to read. The dynamic changes to the presentation (not changes to DOM) are .class driven. When #viewFlags is checked .hide is applied to trs that have no checkbox checked and the table is given the .freeze class so no flags can be unchecked when #viewFlags is checked.

const loopRows = (NodeList, hide = false) => {
  NodeList.forEach(n => {
    if (n.checked && hide) {
      n.closest('tr').className = '';
    } else if (!n.checked && hide) {
      n.closest('tr').className = 'hide';
    } else {
      n.closest('tr').className = '';
    }
  })
};
      
const filterRows = e => {
  let chkAll = document.querySelectorAll('.chx');
  const vF = e.target;
  if (vF.checked) {
    vF.closest('table').className = 'freeze';
    loopRows(chkAll, true);
  } else {
    vF.closest('table').className = '';
    loopRows(chkAll);
  }
};

document.querySelector('#viewFlags').addEventListener('change', filterRows);
.hide {
  visibility: hidden
}

.chx+span::before {
  content: '\0a\002690';
}

.chx:checked+span::before {
  content: '\0a\002691'
}

.freeze .chx {
  pointer-events: none;
}
<table>
  <thead>
    <tr>
      <th>
         <input id='viewFlags' type="checkbox">
          <label type='checkbox'>⛿</label>
      </th>
      <th>No.</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input class='chx' type="checkbox"><span></span></td>
      <td>
        <div>ONE</div>
      </td>
    </tr>
    <tr>
      <td><input class='chx' type="checkbox"><span></span></td>
      <td>
        <div>TWO</div>
      </td>
    </tr>
    <tr>
      <td><input class='chx' type="checkbox"><span></span></td>
      <td>
        <div>THREE</div>
      </td>
    </tr>
    <tr>
      <td><input class='chx' type="checkbox"><span></span></td>
      <td>
        <div>FOUR</div>
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

dale landry
dale landry

Reputation: 8610

Run an event listener on the main select and if it is checked, get the checked values of the select elements within the table and use a class to set their display to none.

Explanations in code snippit.

Added an option to remove elements from the selected list that are selected while down is checked.

let down = document.getElementById('down');
let select = document.querySelectorAll('tr input[type="checkbox"]');

function isChecked(e) {
  // if event target #down, is checked run over 
  // each tr select and see which is checked
  if (e.target.checked) {
    select.forEach(checkBox => {
      // toggle classList for select that are NOT checked
      // add a helper class to add a display of none
      if (!checkBox.checked) {
        checkBox.closest('tr').classList.toggle('display-none')
      }
    })
  } else {
    // else if #down is not checked, remove all helper class of display none
    select.forEach(checkBox => {
      checkBox.closest('tr').classList.remove('display-none');
    })
  }
}
// optional for when you want to remove from the selected list while 
// parent #down is selected
// function to remove selected table rows when the main is selected
// and the target select is then unchecked
function removeUnchecked(e) {
  if (down.checked && !e.target.checked) {
    e.target.closest('tr').classList.add('display-none')
  }
}
// event listener for main select #down
down.addEventListener('change', isChecked);
// maybe you remove a tables check on a select while #down select is checked
select.forEach(sel => addEventListener('change', removeUnchecked));
.display-none {
  display: none;
}
<div class="parent-container">
  <span class="text-default">
    <input type="checkbox" class="down-checkbox" id="down" />
    <label for="down">Check to show Flags only</label>
  </span>
  <table class="table1">
    <thead>
      <tr>
        <th>Flag</th>
        <th>No.</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><input type="checkbox" />&nbsp;</td>
        <td><span class="whatever">ONE</span></td>
      </tr>
      <tr>
        <td><input type="checkbox" />&nbsp;</td>
        <td><span class="whatever">TWO</span></td>
      </tr>
      <tr>
        <td><input type="checkbox" />&nbsp;</td>
        <td><span class="whatever">THREE</span></td>
      </tr>
      <tr>
        <td><input type="checkbox" />&nbsp;</td>
        <td><span class="whatever">FOUR</span></td>
      </tr>
    </tbody>
  </table>
</div>

Upvotes: 0

Gamedroit
Gamedroit

Reputation: 385

const downCheckBox = document.querySelector("#down");
const checkBoxes = document.querySelectorAll(".table1 input[type=checkbox]");

downCheckBox.addEventListener("click", () => {
    for (checkbox of checkBoxes) {
        checkbox.parentNode.parentNode.hidden = downCheckBox.checked && !checkbox.checked;
    }
})
<span class="text-default">
    <input type="checkbox" class="down-checkbox" id="down" />
    <label for="down">Check to show Flags only</label>
</span>
<table class="table1">
    <thead>
        <tr>
            <th>Flag</th>
            <th>No.</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><input type="checkbox" />&nbsp;</td>
            <td><span class="whatever">ONE</span></td>
        </tr>
        <tr>
            <td><input type="checkbox" />&nbsp;</td>
            <td><span class="whatever">TWO</span></td>
        </tr>
        <tr>
            <td><input type="checkbox" />&nbsp;</td>
            <td><span class="whatever">THREE</span></td>
        </tr>
        <tr>
            <td><input type="checkbox" />&nbsp;</td>
            <td><span class="whatever">FOUR</span></td>
        </tr>
    </tbody>
</table>

Upvotes: 0

mplungjan
mplungjan

Reputation: 178109

Here is an example

const rows = document.querySelectorAll(".table1 tbody tr")
document.getElementById("down").addEventListener("click",function() {
  rows.forEach(row => row.hidden = this.checked && !row.querySelector("input").checked)
})
<span class="text-default">
  <input type="checkbox" class="down-checkbox" id="down" />
  <label for="down">Check to show Flags only</label>
</span>
<table class="table1">
  <thead>
    <tr>
      <th>Flag</th>
      <th>No.</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">ONE</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">TWO</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">THREE</span></td>
    </tr>
    <tr>
      <td><input type="checkbox" />&nbsp;</td>
      <td><span class="whatever">FOUR</span></td>
    </tr>
  </tbody>
</table>

Upvotes: 2

Related Questions