简体   繁体   中英

Stop checkbox being checked twice when inside an li with a click event

I'm writing a simple dropdown menu with jQuery and each item has a checkbox. When I click on an li element the checkbox is selected. However if I click on the checkbox itself, it does not select because it is effectively checked twice. How can I stop this happening?

jsFiddle: http://jsfiddle.net/ZEp7V/

HTML:

<div id="dropdown">Channels</div>
<ul class="droplist">
    <li>News <input type="checkbox" /></li>
    <li>Sport <input type="checkbox" /></li>
    <li>Science <input type="checkbox" /></li>
    <li>Health <input type="checkbox" /></li>
    <li>All</li>
</ul>

CSS:

div#dropdown {
    border: 1px solid #000;
    width: 150px;
    height: 20px;
    line-height: 20px;
    padding: 10px;
    cursor: pointer;
}

ul.droplist {
    display: none;
    width: 170px;
    border: 1px solid #000;
    border-bottom: none;
    list-style-type: none;
    padding: 0px;
    margin: 0px;
    position: absolute;
    background-color: #fff;
}

ul.droplist li {
    border-bottom: 1px solid #000;
    padding: 10px;
    cursor: pointer;
}

ul.droplist li input {
    float: right;
}

JS:

$(document).ready(function(){

    $("#dropdown").click(function() {
        $(this).next().slideToggle(200);
    });

    $(".droplist li").click(function(e) {
        // Toggle the checkbox
        var input = $(this).children("input");
        $(input).prop("checked", !$(input).prop("checked"));
    });

    $(".droplist li:last").click(function () {
        // Select all boxes
        var check = $('.droplist li input:not(:checked)').length;
        $(".droplist li input").prop("checked", check);
    });

});

You can stop the propagation of the event at the checkbox:

$(".droplist li :checkbox").click(function (e) {
    e.stopPropagation();
});

This will prevent the event from bubbling up the DOM tree to the parent li element (where, as you say, it triggers the event handler bound to it).


As a side note, you could modify your code to take advantange of event delegation, which is more efficient since there's only one event handler instead of one for each li element. For example:

$(".droplist").on("click", "li", function (e) {
    // Toggle the checkbox
    var input = $(this).children("input");
    $(input).prop("checked", !$(input).prop("checked"));
});

See the .on() method for more details.

Wrap the checkboxes with labels (labels share the browser native click event with the input)

<li><label for="news_input">News <input type="checkbox" id="news_input" /></label></li>
<li><label for="sport_input">Sport <input type="checkbox" id="sport_input" /></li>
<li><label for="science_input">Science <input type="checkbox" id="science_input" /></li>
<li><label for="health_input">Health <input type="checkbox" id="health_input" /></li>

And get rid of this behaviour

$(".droplist li").click(function(e) {
   // Toggle the checkbox
  var input = $(this).children("input");
  $(input).prop("checked", !$(input).prop("checked"));
});

Like this, you should be fine. The problem with your solution is that the native browser checkbox function and jQuery kill each other as soon as a user hits the input with a click. (Browser checks the checkbox, jQuery unchecks it)

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