简体   繁体   中英

Why does a checkbox's “checked” attribute return the opposite of it's actual value on click event?

I've got the following HTML

<li><input type="checkbox" /><label>This is the label!</label></li>

I bound a click event to the li, and let the click event bubble up to the li before doing anything else.

$('li').each(function(i){
  var item = $(this);
  var checkbox = $("input[type='checkbox']", item);

  item.bind('click', function(e){
    var isChecked = checkbox.is(':checked');
    console.log(isChecked);
    e.stopPropagation();
  });
});

Starting with an unchecked checkbox, when the click event fires, isChecked returns true when I click on the checkbox, but returns false when I click on the label or li. Does anyone know why?

[EDIT:] To demonstrate the issue, have a look at this http://jsfiddle.net/nYbf6/2/ .

  1. Click on the checkbox in the first li.
  2. Click inside the second li, but not on a label or checkbox.

Notice that you can never toggle the checkbox by clicking on the checkbox because the 'checked' attribute always returns what it is not when clicking on the checkbox.

[EDIT:] Found the answer here today: http://www.bennadel.com/blog/1525-jQuery-s-Event-Triggering-Order-Of-Default-Behavior-And-triggerHandler-.htm . I'm not fond of the solution, but it's better than no solution.

the click event of a checkbox fires before the value is changed. This way, if you return false when you override the click event, it stops the checkbox from changing it's value. You should change the event to fire onclick of the checkbox, not the li that contains it.

You would do better to fetch the appropriate checkbox as part of the click , like this:

$('li').click(function(e) {
  var isChecked = $(':checkbox:checked', this).length > 0;
  console.log(isChecked);
  e.stopPropagation();
});

This finds the checkbox in the <li> that was clicked when it was clicked.

As for the why part, if you're clicking on the checkbox, you're setting it to true, then the event propagates to the li which determines the checkbox is indeed checked. With an unchecked box if you're clicking on the label, it's not checking the box, so it's still false. If you checked the box then clicked the label, you'll see true coming back, because now it's checked.

If you're expecting the label to check the checkbox, you need to relate it using label's for attribute, like this:

<li>
  <input id="myInput" type="checkbox" />
  <label for="myInput">This is the label!</label>
</li>

Then the browser will handle the connection, click the label will toggle the checkbox.

Try this:

<li>
  <input type='checkbox' value='foo' id='myFavoriteCheckbox'>
  <label for='myFavoriteCheckbox'>The Label</label>
</li>

Now when you click on the label, the checkbox will be affected. Bind the handler to the checkbox and check .attr('checked') and you'll find that even on click events the value of the checkbox will be correct. Note also that that's true even if you decide to stop propagation and prevent default for the event. In other words, if you handle a click event and decide to prevent the default action, your handler will still see the value of "checked" set to what it would be if you did not stop the default action.

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