Make dynamically generated checkbox click work even when parent div is clicked

3.8k views Asked by At

I have dynamically generated checkbox within dynamically generated row. I attach delegated event ('click') listener to the entire row.

And everything works perfectly fine - I toggle checkbox status by clicking any place within the row, except just one little thing - clicking checkbox itself does not toggle its status.

Below is my sample code. Any ideas?

//Generate dynamically div row encompassing checkbox and label
$('#wraper').append(`
<div id="row">
 <label>This is the checkbox</label>
  <input type="checkbox"></input>
</div>
<br>
<span class="msg"></span>
`);
//Attach delegated event listener to entire row
$('#wraper').on('click', '#row', function(){
 //Toggle checked attribute
 $('#row [type="checkbox"]').get(0).checked = !$('#row [type="checkbox"]').get(0).checked;
  //Display checked status after click
 $('#wraper .msg').text(`Checkbox status is ${$('#row [type="checkbox"]').get(0).checked}`);
});
<!doctype html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
  <div id="wraper"></div>
</body>
</html>

5

There are 5 answers

1
adiga On BEST ANSWER

As mentioned in the comments, remove the click logic from your code. It's immediately overwriting the default HTML functionality. If your intention is to get the checkbox checked even when the label is clicked, you can use the for attribute and point to the checkbox's id:

Update: If you want to the checkbox checked anywhere from the parent div, then add a click handler to the parent. If the click target is not a checkbox, force the checkbox to be checked. If the target is a checkbox, don't do anything.

$('#wraper').append(`
<div id="row">
 <label>This is the checkbox</label>
  <input type="checkbox"></input>
</div>
<br>
<span class="msg"></span>
`);

$('#wraper').on('click', '#row', function(e) {
  /* If the clicked element is not a checkbox,
      then force the check via jquery
  */
  if (e.target.type !== 'checkbox') {
    $(this).find('input').prop('checked', !$(this).find('input').prop('checked'))
  }
    // Display checked status after click
  $('#wraper .msg').text(`Checkbox status is ${$('#row [type="checkbox"]').get(0).checked}`);
  
});


$("#checkbox-test").change(function() {
  $('#wraper .msg').text(`Checkbox status is ${this.checked}`);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wraper"></div>

0
tymeJV On

The reason it does nothing is because if you click exactly on the checkbox, your code immediately resets the box back to its previous state. You can solve this by using the for attribute on your label - and then just using a change event on the checkbox itself:

Refactored HTML:

<div id="row">
    <label for="checkbox1">This is the checkbox</label>
    <input type="checkbox" id="checkbox1"></input>
</div>

Updated JS:

$("#checkbox1").change(function() {
    $('#wraper .msg').text(`Checkbox status is ${this.checked}`);
}).change(); //execute immediately so the text displays.
0
Shidersz On

Your main problem is that when you click the checkbox, the event is propagated to the row, so this will be the same that clicked the checkbox two times. The solution is to stopPropagation() of the event to the parent row when the checkbox is clicked:

// Generate dynamically div row encompassing checkbox and label

$('#wraper').append(`
    <div id="row">
      <label>This is the checkbox</label>
      <input type="checkbox"></input>
    </div>
    <br>
    <span class="msg"></span>
`);

// Attach delegated event listener to entire row.

$('#wraper').on('click', '#row', function()
{
    // Toggle checked attribute.

    $('#row [type="checkbox"]').get(0).checked = !$('#row [type="checkbox"]').get(0).checked;

    // Display checked status after click.

    $('#wraper .msg').text(`Checkbox status is ${$('#row [type="checkbox"]').get(0).checked}`);
});

$('#wraper').on('click', 'input[type="checkbox"]', function(e)
{
    $('#wraper .msg').text(`Checkbox status is ${$('#row [type="checkbox"]').get(0).checked}`);
    e.stopPropagation();
});
<!doctype html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
  <div id="wraper"></div>
</body>
</html>

0
AudioBubble On

Whoops! Don't worry friend. Simple mistake, once the user clicked on the checkbox, the default action will be to check the box. Your code here, performs this "check" action a second time. So you're immediately checking and then unchecking the box!

There are two possible fixes for you. Either, you can simply stop checking/un-checking the box in your code, in other words comment out this line here:

//$('#row [type="checkbox"]').get(0).checked = !$('#row [type="checkbox"]').get(0).checked;

Or you can continue to do so, but you must disable the default HTML action from occurring, using the function

`enter code here`event.preventDefault()

Sadly, I couldn't get this to work with jQuery... I'm not all well versed in it myself but I'm sure someone else will comment how to do this below!

0
Taplar On

You can just skip the checkbox toggle if the element clicked was the checkbox.

//Generate dynamically div row encompassing checkbox and label
$('#wraper').append(`
<div id="row">
 <label>This is the checkbox</label>
  <input type="checkbox"></input>
</div>
<br>
<span class="msg"></span>
`);
//Attach delegated event listener to entire row
$('#wraper').on('click', '#row', function(e) {
  var $checkbox = $('#row [type="checkbox"]').eq(0);
  
  //Toggle checked attribute
  if (!$checkbox.is(e.target)) {
    $checkbox.prop('checked', !$checkbox.prop('checked'));
  }
  
  //Display checked status after click
  $('#wraper .msg').text(`Checkbox status is ${$checkbox.prop('checked')}`);
});
<!doctype html>
<html>

<head>
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>

<body>
  <div id="wraper"></div>
</body>

</html>