Search code examples
javascriptjqueryevent-delegation

how to ignore checkbox inside td


I am using jQuery's event delegation to add a click event to table rows. I also have a checkbox in the first td of the row. When I click anywhere in the row everything works as expected. However, I don't want the event to work when I click in the checkbox. I've tried using the :not() selector but perhaps I am missing something as I am still triggering the event when I click in the checkbox.


HTML

<tr>
    <td>
        <div class="myCheckbox"><input type="checkbox" name="userName" /></div>
    </td>
    <td><a href="/go/to/user/profile"></a></td>
    <td>more info</td>
    <td>more info</td>
    <td>more info</td>
</tr>

jQuery

$('table tr:not(':checkbox')').on('click', 'td', function(event) {

    // Do something
});



Can I get help fixing what I am attempting to do please?


Solution

  • Two options (both involve removing the tr:not stuff from your existing code, which as you say doesn't work — tr elements can't be checkboxes, and :not checks the element, not its contents):

    1. Add an event handler to the checkbox that calls e.stopPropagation. Then the click event won't reach the row. You can do that either directly or via delegation. Here's a live example going direct. If you go indirect, be sure to test clicking labels that activate the checkbox (if you're going to have them) on all of the browsers you intend to support.

      or

    2. Add this to your handler:

      if ($(event.target).is('input[type=checkbox]')) {
          return;
      }
      

      E.g.:

      $('table').on('click', 'td', function(event) {
      
          if ($(event.target).is('input[type=checkbox]')) {
              return;
          }
      
          // Logic here
      });
      

      That works by testing the source of the event to see if it's a checkbox, and bailing early.

    In both cases, if you use a label to activate the checkbox, you may need to do the same thing for the label.

    I got curious about what #2 would look like handling labels, and it turns out it's enough code to move into a function, but not hard &mdash probably how I'd go: Live example | source

    jQuery(function($) {
    
      // The table cell click handler
      $("table").on("click", "td", function(e) {
        // Is the source a checkbox or the label for
        // one?
        if (isCheckbox($(e.target))) {
          return;
        }
    
        // Normal handling
        $(this).toggleClass("foo");
      });
    
      // Function to test whether the source is a
      // checkbox, or the label of a checkbox
      function isCheckbox($elm) {
        var chkid;
    
        if ($elm.is("input[type=checkbox]")) {
          return true;
        }
        if ($elm.is("label")) {
          chkid = $elm.attr("for");
          if (chkid) {
            return $("#" + chkid).is("input[type=checkbox]");
          }
          return !!$elm.find("input[type=checkbox]")[0];
        }
        return false;
      }
    
    });