2

I need for all checkbox to be checked or unchecked when either header cell (yellow color) or checkbox in header cell is clicked.

  $('th, td').click(function (event) {
 
if (!$(event.target).is('input')) {

    $('input:checkbox', this).prop('checked', function (i, value) {
     
        //console.log('i', i)
      //console.log('value', value)
      //console.log('this', this)
      
      //$(':checkbox').prop('checked', this.checked); // disable this line for working checkedbox when cell is clicked.
      //$(':checkbox[class="check_all"]').prop("checked", $(this).prop("checked"));
      
       return !value;
     });
  }
  });
<style>
  th, td {border:1px solid black;padding:20px;}
</style>

<table>
<tr>
    <th>Header. Nothing should happen will click cell in this column</th>
    <th bgcolor= "yellow"><input id="header" type="checkbox"/></th>
</tr>
<tr>
    <td>Row 1</td>
    <td><input class="check_all" type="checkbox"/></td>
</tr>
<tr>
    <td>Row 2</td>
    <td><input class="check_all" type="checkbox"/></td>
</tr>    
</table>

jsFiddle : https://jsfiddle.net/ockr05d9/

Please assist me.

sg552
  • 1,521
  • 6
  • 32
  • 59
  • What exactly is the expected behavior? Please elaborate. – Unmitigated Jul 12 '23 at 20:40
  • Does this answer your question? [How to implement "select all" check box in HTML?](https://stackoverflow.com/questions/386281/how-to-implement-select-all-check-box-in-html) – Heretic Monkey Jul 12 '23 at 22:18
  • @Unmitigated I need for all checkbox to be checked or unchecked when either header cell (yellow color box) or checkbox in header cell (yellow color box) is clicked. – sg552 Jul 13 '23 at 02:52
  • @HereticMonkey I actually have working code when checked box in header cell is clicked. What I need now is when `header cell` is clicked, all checkbox will be checked or unchecked. – sg552 Jul 13 '23 at 02:55
  • Unsurprisingly, there are many duplicates for that scenario as well: [if some checkboxes are 'checked' then check all javascript](https://stackoverflow.com/q/61818723/215552), [How to check if all checkboxes are unchecked](https://stackoverflow.com/q/14800954/215552), [Select all checkbox to be checked if all checkboxes are checked](https://stackoverflow.com/q/45540344/215552)... – Heretic Monkey Jul 13 '23 at 16:05

1 Answers1

0
  • Use data-* attribute on your checkbox to assign each to a specific family, namely: data-toggle-family for the "head parent" checkbox and data-family for the associated checkboxes
  • If needed, for a better UI,UX use the indeterminate state for the "parent head checkbox" (read more in this CSS Tricks article where examples cover use-cases for tree structure)

Example:

// Parent
$("[data-toggle-family]").on("input", function() {
  const family = $(this).data("toggle-family");
  const $children = $(`[data-family="${family}"]`);
  $children.prop({
    checked: this.checked
  });
});

// Related children
$("[data-family]").on("input", function() {
  const family = $(this).data("family");
  const $parent = $(`[data-toggle-family="${family}"]`);
  const $siblings = $(`[data-family="${family}"]`);
  const $siblingsCkd = $siblings.filter(":checked");
  const allChecked = $siblingsCkd.length === $siblings.length;
  const allUnchecked = $siblingsCkd.length === 0;
  $parent.prop({
    checked: allChecked,
    indeterminate: !allChecked && !allUnchecked
  });
});

// Addon: Make entire parent row clickable
$("tr:has([data-toggle-family])").on("click", function(evt) {
  const $parent = $(this).find("[data-toggle-family]");
  if ($(evt.target).is($parent)) return;
  $parent.prop("checked", !$parent.prop("checked"));
  $parent.trigger("input");
});
<table>
  <tbody>
    <tr>
      <th>Header 1</th>
      <th><input data-toggle-family="one" type="checkbox"></th>
    </tr>
    <tr>
      <td>Row 1</td>
      <td><input data-family="one" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 2</td>
      <td><input data-family="one" type="checkbox"></td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th>Header 2</th>
      <th><input data-toggle-family="two" type="checkbox"></th>
    </tr>
    <tr>
      <td>Row 1</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 2</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 3</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
  </tbody>
</table>

<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

PS:
Not needed for the JS part to work, but remember to assign name="someName" attribute to your children input elements. If you want you can also rewrite the above to work in relation to that name attribute:

<input data-toggle-family="one" type="checkbox">
<input name="one" type="checkbox">
<input name="one" type="checkbox">
<input data-toggle-family="two" type="checkbox">
<input name="two" type="checkbox">
<input name="two" type="checkbox">

Not needed for this example, but it's useful to always explicitly use the tbody element. The browser will create it regardless. You can also create more than one TBODY if needed. Also, you can use the th element for a better markup syntax — where needed.

Pure JavaScript solution

Nowadays jQuery is not necessary. Here's a remake in JavaScript without any external library:

// DOM utils:
const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);

// Parent
els("[data-toggle-family]").forEach(elParent => {
  elParent.addEventListener("input", () => {
    const family = elParent.dataset.toggleFamily;
    const elsChildren = els(`[data-family="${family}"]`);
    elsChildren.forEach(elChild => elChild.checked = elParent.checked);
  });
});

// Related children
els("[data-family]").forEach(elChild => {
  elChild.addEventListener("input", () => {
    const family = elChild.dataset.family;
    const elParent = el(`[data-toggle-family="${family}"]`);
    const elsSiblings = els(`[data-family="${family}"]`);
    const siblingsCkd = [...elsSiblings].filter(el => el.checked);
    const allChecked = siblingsCkd.length === elsSiblings.length;
    const allUnchecked = siblingsCkd.length === 0;
    elParent.checked = allChecked;
    elParent.indeterminate = !allChecked && !allUnchecked;
  });
});

// Addon: Make entire parent row clickable
els("tr:has([data-toggle-family])").forEach(elTr => {
  elTr.addEventListener("click", (evt) => {
    if (evt.target.closest(`[data-toggle-family]`)) return
    const elParent = el(`[data-toggle-family]`, elTr);
    console.log(111)
    elParent.checked = !elParent.checked;
    elParent.dispatchEvent(new Event("input", {bubbles: true}));
  });
});
<table>
  <tbody>
    <tr>
      <th>Header 1</th>
      <th><input data-toggle-family="one" type="checkbox"></th>
    </tr>
    <tr>
      <td>Row 1</td>
      <td><input data-family="one" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 2</td>
      <td><input data-family="one" type="checkbox"></td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th>Header 2</th>
      <th><input data-toggle-family="two" type="checkbox"></th>
    </tr>
    <tr>
      <td>Row 1</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 2</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
    <tr>
      <td>Row 3</td>
      <td><input data-family="two" type="checkbox"></td>
    </tr>
  </tbody>
</table>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • Apologies for the confusion. I actually have working code when checked box in header cell is clicked. What I need now is when `header cell` is clicked (area around the header checkbox), all checkbox will be checked or unchecked. – sg552 Jul 13 '23 at 03:01
  • @sg552 The simplest is to use a ``, make is CSS `display: block;`, and use `` for the family checkbox. – Roko C. Buljan Jul 13 '23 at 08:23
  • Or by using jQuery: I'll edit the examples above for this ones. – Roko C. Buljan Jul 13 '23 at 08:25