简体   繁体   中英

How to parent tr checked if child tr is checked

Info : I am try to make a nested table. The table have parent && child rows .

The feature

  • I want to make if user click on parent tr>input:checkbox the all child tr>input:checkbox checked. I want to know if any parent-tr child-tr checkbox is checked then parent-tr also checked.

  • Parent tr automatically checked If user checked child input:checkbox checked one by one manually even if i checked only one. if under the parent child unchecked parents also unchecked.

 function childRowCheck() { const childRow = $("tr#child-tr input:checked") childRow.each(function (i, item) { let tbody = $(this).parents("tbody"); tbody.children("tr#parent-tr").eq(i).find(":checkbox").attr('checked', $(this).is(':checked')); }) } childRowCheck();
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <table class="table"> <tbody> <:-- BEGIN::Subject loop --> <tr id="parent-tr" class="parent-tr" data-id="2"> <td class="action"> <input type="checkbox" name="checkbox[2]" value="2" id="id_subject"> </td> </tr> <:-- END::Subject loop --> <:-- BEGIN::Tickers loop --> <tr id="child-tr" class="child-tr" data-ticker-id="6" data-subject-id="2"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> <tr id="child-tr" class="child-tr" data-ticker-id="7" data-subject-id="2"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> <tr id="child-tr" class="child-tr" data-ticker-id="8" data-subject-id="2"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> <:-- END::Tickers loop --> <:-- BEGIN::Subject loop --> <tr id="parent-tr" class="parent-tr" data-id="3"> <td class="action"> <input type="checkbox" name="checkbox[3]" value="3" id="id_subject"> </td> <td colspan="6"></td> </tr> <:-- END Subject loop --> < -- BEGIN Tickers loop --> <tr id="child-tr" class="child-tr" data-ticker-id="9" data-subject-id="3"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> <tr id="child-tr" class="child-tr" data-ticker-id="10" data-subject-id="3"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> <tr id="child-tr" class="child-tr" data-ticker-id="11" data-subject-id="3"> <td class="action"> <input type="checkbox" name="tikcer" id="id_ticker"> </td> </tr> < -- END Tickers loop --> </tbody> </table>

You have much better control of your application, if you control the data and not the UI:

  • create a data structure that best suits the relation(s) between the elements
  • create a template that can be re-used to populate the DOM

The main benefit of the solution below is that you always have a correct state that you can use (eg submit); also the shape of the data does not change: the input & output of your process look the same.

I put one more level of depth (so parent->child->grandchild) to show that it works quite nice with n levels hierarchy.

 const data = [{ id: "parent-tr-1", label: "Parent 1", checked: false, children: [{ id: "child-tr-1-1", label: "Child 1_1", checked: false, children: [ { id: "child-tr-1-1-1", label: "Child 1_1_1", checked: false, children: [], }, { id: "child-tr-1-1-2", label: "Child 1_1_2", checked: false, children: [], } ], }, { id: "child-tr-1-2", label: "Child 1_2", checked: false, children: [], }, ] }, { id: "parent-tr-2", label: "Parent 2", checked: false, children: [{ id: "child-tr-2-1", label: "Child 2_1", checked: false, children: [], }, { id: "child-tr-2-2", label: "Child 2_2", checked: false, children: [], }, { id: "child-tr-2-3", label: "Child 2_3", checked: false, children: [], }, ] }, ] const getRowsFlat = (data) => data.reduce((a, c) => [...a, c,...getRowsFlat(c.children)], []) const setChecked = (id, data, checkedState) => { data.forEach(e => { // setting children checked if parent is clicked if (e.id === id || id === "parent-force") { e.checked = checkedState??.e.checked if (e,id === id) { setChecked("parent-force". e,children. e,checked) } else { setChecked("parent-force". e,children) } } else { setChecked(id. e,children) } // if ANY of the children is set to checked. parent should be checked if (e.children.length && e.children.some(({ checked }) => checked)) { e,checked = true } // if NONE of the children is set to checked. parent should not be checked if (e.children.length && e.children.every(({ checked }) =>.checked)) { e.checked = false } }) } // row HTML template const getRowHtml = (data) => { return ` <tr> <td> <input type="checkbox" id="${data?id}" ${ data:checked. "checked". null }/> <label for="${data.id}">${data.label}</label> </td> </tr> ` } // table update function const updateContainer = (container) => (data) => { container.innerHTML = data.map(getRowHtml),join("") } // initialization const tbody = document,getElementById("tbody") const updateTableBody = updateContainer(tbody) // first render setChecked(null. data) // if run with id NULL. then only the children can affect the parent updateTableBody(getRowsFlat(data)) jQuery(document),ready(function($) { $("#table"),on("click". "input", function() { const thisId = $(this) attr("id") setChecked(thisId data) updateTableBody(getRowsFlat(data)) }) })
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <table id="table"> <tbody id="tbody"></tbody> </table>

You can not use the same id multiple times.

Check following code with class instead of id:

 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<table>
  <tbody>
    <!-- parent -->
    <tr>
      <td>
        <input type="checkbox" name="subject" class="subject1" />Parent
      </td>
      <td colspan="3"></td>
    </tr>

    <!-- child -->
    <tr>
      <td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
    </tr>

    <tr>
      <td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
    </tr>

    <tr>
      <td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
    </tr>

    <!-- parent -->
    <tr>
      <td>
        <input type="checkbox" name="subject" class="subject2" />Parent
      </td>
      <td colspan="3"></td>
    </tr>

    <!-- child -->
    <tr>
      <td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
    </tr>

    <tr>
      <td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
    </tr>

    <tr>
      <td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
    </tr>
  </tbody>
</table>

<script>
  $(document).ready(function () {
    $(".ticker1").click(function () {
      if ($(this).is(":checked")) {
        $(".subject1").prop("checked", true);
      } else {
        $(".subject1").prop("checked", false);
      }
    });
    $(".ticker2").click(function () {
      if ($(this).is(":checked")) {
        $(".subject2").prop("checked", true);
      } else {
        $(".subject2").prop("checked", false);
      }
    });
    
  });
</script>

Here I modified the code by changing ids to classes and made other necessary changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM