skip to Main Content

I am trying to toggle the checked property of a checkbox when I click on a table row but so far with my solution I am unable to achieve it. This is how the HTML looks like:

<table id="chkContainer">
  <tr id="row-1">
    <td><input type="checkbox" value="1"></td>
    <td>1st Row</td>
    <td>Not clickable</td>
  </tr>
  <tr id="row-2">
    <td><input type="checkbox" value="2"></td>
    <td>2nd Row</td>
    <td>Not clickable</td>
  </tr>
  <tr id="row-3">
    <td><input type="checkbox" value="3"></td>
    <td>3rd Row</td>
    <td>Not clickable</td>
  </tr>
</table>

and here is the jQuery code I have built:

$(function() {
  $("#chkContainer tr > td").on("click", function() {
    const tr = $(this).closest('tr')
    const chk = tr.find('input:checkbox').prop("checked", true);

    tr.toggleClass('red', chk.checked);
  })
})

What is not working? I can check the checkbox when clicking the row for the first time but when I click the same row once again the checkbox remains checked. I am pretty sure my issue is this line: $(":checkbox[value=" + id + "]").prop("checked", true) since I am always setting it to true but I am not sure how to set it to false when the same row gets a new click.

How do I avoid this behavior from happening if I click in the last td which generally contains buttons or user actions?

I could not find any solution to this or I am very bad at searching on Google 😐

here is a Fiddle so you can play with it.

2

Answers


  1. You’re mixing jQuery with vanilla.

    chk.checked would be vanilla JS but chk is jQuery object. Use jQuery’s chk.is(':checked');

    Best practice is to prepend jQuery objects with $ so you don’t get mixed up. i.e. this is not ambiguous

    const chk  = document.querySelector('.somecheckbox');
    const $chk = $('.somecheckbox');
    

    Also you’re going to have an issue, once it works, when you check the actual checkbox, because the logic will toggle twice since you checked the box manually and the click propagates to the tr which then toggles it programmatically. We need the click to propagate in this case because clicking the tr triggers a colour change too, but we can work around it.

    $(function() {
      $("#chkContainer tr > td").on("click", function(e) {
        const $tr = $(this).closest('tr');
        const $chk = $tr.find('input:checkbox');
        // make sure it's not the checkbox that was clicked before toggling it 
        // otherwise we're undoing the manual toggle
        if (!$(e.target).is($chk)){
          $chk.prop("checked", !$chk.is(':checked'));
       }
       $tr.toggleClass('red', $chk.is(':checked'));
      });
    })
    

    The fiddle

    Login or Signup to reply.
  2. when the user clicks on the checkbox, it switches its state.
    but in doing so it also clicks on a td element, which you have programmed to force the checkbox to true.

    const tb_chkContainer = document.querySelector('#chkContainer')
    
    tb_chkContainer.addEventListener('click', (evt) =>
      {
      let tr    = evt.target.closest('tr')
        , chkBx = tr.querySelector('input[type="checkbox"]')
        ;
      if (evt.target.matches('td'))  // only <td> (not checkbox element)
        {
        chkBx.checked = !chkBx.checked; // switch checkbox value
        }
      tr.classList.toggle('red', chkBx.checked );
      })
    .red {
      background : red;
      }
    <table id="chkContainer">
      <tr id="row-1">
        <td><input type="checkbox" value="1"></td>
        <td>1st Row</td>
        <td>Not clickable</td>
      </tr>
      <tr id="row-2">
        <td><input type="checkbox" value="2"></td>
        <td>2nd Row</td>
        <td>Not clickable</td>
      </tr>
      <tr id="row-3">
        <td><input type="checkbox" value="3"></td>
        <td>3rd Row</td>
        <td>Not clickable</td>
      </tr>
    </table>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search