0

Using Bootstrap 3.3.6, JQuery 1.11.3

I'm having an issue with a small section, specifically regarding selecting and deselecting a checkbox when the user clicks on the row.

jsfiddle here: http://jsfiddle.net/0ogdt9s7/1/

html

<div id="not-working">
  <h3>
  Click the text, then click the box
  </h3>
  <div class="selection-row" data-id="20">
    <div class="col-md-5">Data 20</div>
    <div class="col-md-2">
      <input type="checkbox" name="selectedDudes[]" value="20" id="checkbox-20">
    </div>
  </div>
  <div class="selection-row" data-id="22">
    <div class="col-md-5">Data 22</div>
    <div class="col-md-2">
      <input type="checkbox" name="selectedDudes[]" value="22" id="checkbox-22">
    </div>
  </div>
</div>

js

$(document).ready(function() {

  $(document).on("click", "div.selection-row", function() {
    var $cb = $('input[type="checkbox"]', $(this)), is_on = $cb.prop('checked');
    if (is_on) {
      //if its already checked, uncheck it
      $cb.prop('checked', false);
    } else {
      //if its not checked, check it
      $cb.prop('checked', true);
    }
  });
});

The row selection works great, but if you click on the checkbox inside the row, the checkbox does not change. Clicking on 'Data' will change it correctly, but the checkbox is doing nothing.

Important to note:

It must reside inside $(document).on() because this is inside a popup which is displayed through AJAX.

I'm assuming this is something super simple, but I just cannot find it. Any help is appreciated.

2
  • 1
    What happens if you add onclick="return false" to the checkbox input to stop it from responding to the onclick event. I'm just wondering if both row and input click events are triggering toggling the checkbox on then off or off then on in one click. Commented Dec 15, 2016 at 19:51
  • doesn't seem to affect it: jsfiddle.net/0ogdt9s7/5 Commented Dec 15, 2016 at 20:03

5 Answers 5

3

You are getting an unexpected result because of the Bubbling phase.

The Bubbling phase of an event triggers all element's parents that are listening to the event from bottom to top:

enter image description here

In your case, when the user clicks the checkbox first time, it gets selected. Then the Blubbling phase takes place and starts to search for the closest parent that is listening to the event, if there's any, its handler (function) gets executed. You have one: selection-row.

The handler of the .selection-row element reverts what the default behavior of the checkbox did, so it's like the user hasn't done nothing.

If what you want is that when the user clicks the Data 20 or the Data 22 and the respective checkbox gets selected, you don't need to use javascript. A label element should solve that:

  <div class="selection-row" data-id="20">
  <div class="col-md-5"><label for="checkbox-20" >Data 20</label></div>
    <div class="col-md-2">
      <input type="checkbox" name="selectedDudes[]" value="20" id="checkbox-20">
    </div>
  </div>
  <div class="selection-row" data-id="22">
  <div class="col-md-5"><label for="checkbox-22">Data 22</label></div>
    <div class="col-md-2">
      <input type="checkbox" name="selectedDudes[]" value="22" id="checkbox-22">
    </div>
  </div>

Check it out: http://jsfiddle.net/0ogdt9s7/2/

As you said you need the entire row to be clickable, you may check if the original target of the event (the innermost element) is the input and let the default behavior do its job by interrupting the handler with a return;:

$(document).on("click", "div.selection-row", function(e) {
    if ($(e.target).is('input')) return;

    var $cb = $('input[type="checkbox"]', $(this)), is_on = $cb.prop('checked');
    if (is_on) {
      //if its already checked, uncheck it
      $cb.prop('checked', false);
    } else {
      //if its not checked, check it
      $cb.prop('checked', true);
    }
  });

Check this solution: http://jsfiddle.net/0ogdt9s7/6/

Sign up to request clarification or add additional context in comments.

3 Comments

thats an interesting option but the issue is scalability. its using the bootstrap css library, and im using rows of data (with more than just one field), and i want the whole row to be clickable.
Wrap the label around the row. Then clicking anywhere in the row will click the checkbox.
@Barmar the problem is that a div element is not allowed to be inside a label element, even though most browsers will not strictly follow these rules: stackoverflow.com/questions/18609554/….
0

Coworker just solved it with a target check:

http://jsfiddle.net/0ogdt9s7/4/

$(document).ready(function() {
  $(document).on("click", ".selection-row", function(e) {
    var $target = $(e.toElement);
    if (!$target.is('input')) {
      console.log($target);
      var $cb = $('input[type="checkbox"]', $(this)),
        is_on = $cb.is(':checked');
      if (is_on) {
        //if its already checked, uncheck it
        $cb.prop('checked', false);
      } else {
        //if its not checked, check it
        $cb.prop('checked', true);
      }
    }
  });
});

Will keep this open for a bit to see if theres a better solution

Comments

0

you could change the element you are listening for clicks on to the text like this:

$(".selector").click(function() {
  $(this).parent().find(".chkbox").trigger("click");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="not-working">
  <h3>
  Click the text, then click the box
  </h3>
  <div data-id="20">
    <div class="col-md-5 selector">Data 20</div>
    <div class="col-md-2">
      <input class="chkbox" type="checkbox" name="selectedDudes[]" value="20" id="checkbox-20">
    </div>
  </div>
  <div data-id="22">
    <div class="col-md-5 selector">Data 22</div>
    <div class="col-md-2">
      <input class="chkbox" type="checkbox" name="selectedDudes[]" value="22" id="checkbox-22">
    </div>
  </div>
</div>

Comments

0

Ok here's a nice clean example with bootstrap's list-group

$(".list-group-item").click(function(event) {
  var target = $(event.target);
  if (target.is("input")) {
    $(this).trigger(click);
  } else {
    $(this).find(".chkbox").trigger("click");
  }
});

<ul class="list-group">
  <li class="list-group-item">
    <input class="chkbox" type="checkbox"> Porta ac consectetur ac
  </li>
</ul>

DEMO

Comments

0

The bubble-up explanation is correct, but a simpler change would be to append event.stopPropagation() to your function

HTML

<input type="checkbox" id="agree-to-terms">
<label for="agree-to-terms">
  Agree to Terms and Conditions
</label>

<div class="proceed-to-checkout">
  <button type="submit" name="checkout" class="checkout-button button full"
  disabled>
  </button>

</div>

Javascript

const checkoutButton = document.querySelector(".checkout-button");

document.querySelector("#agree-to-terms").addEventListener("change",
function() {
  // stop bubble up
  this.checked ? checkoutButton.disabled = false: checkoutButton.disabled = true;
  event.stopPropagation();

});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.