Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are two click events registered in this html/css/jquery

I am trying to style a checkbox list. I've added my styles and they appear correctly when rendered. I want to add a class when the label for the checkbox is clicked. This is my markup and here is the same in a jsfiddle. You can see from my fiddle that two click events are registered with just one click. Why?

html:

<ul>
    <li>
        <label for="test_0" class="">
            <input id="test_0" name="offering_cycle" type="checkbox" value="1"> Fall
        </label>
    </li>
    <li>
        <label for="test_1" class="">
            <input id="test_1" name="offering_cycle" type="checkbox" value="2"> Spring
        </label>
    </li>
    <li>
        <label for="test_2" class="">
            <input id="test_2" name="offering_cycle" type="checkbox" value="3"> Summer
        </label>
    </li>
    <li>
        <label for="test_3" class="">
            <input id="test_3" name="offering_cycle" type="checkbox" value="4"> Other
        </label>
    </li>
</ul>

css:

ul {
    list-style-type:none;
}
label {
    position:relative;
    display:inline-block;
    padding-left:27px;
    height:25px;
}
label:before {
    display:block;
    position:absolute;
    top:-2px;
    margin-left:-28px;
    width:18px;
    height:18px;
    background-color:#fff;
    border-radius:5px;
    border:1px solid #ccc;
    text-align: center;
    color:#fff;
    font-size:18px;
    content:'a';
}
input {
    width:1px;
    height:1px;
    border:0;
    opacity:0;
    float:right;
}

jquery:

$('label[for*=test_]').on('click',function(){
    $(this).toggleClass('testing');
});
like image 795
smilebomb Avatar asked Jun 11 '15 14:06

smilebomb


People also ask

Why is my click event firing twice?

Answers. Post the code of the object you are clicking on, and the event that is firing twice. Usually this is caused by declaring it in the OnClick event, as well as Handles Something.

Why is this jQuery Ajax click event firing multiple times?

an Event will fire multiple time when it is registered multiple times (even if to the same handler). eg $("ctrl"). on('click', somefunction) if this piece of code is executed every time the page is partially refreshed, the event is being registered each time too.

Which method is used to set a click event on a button?

jQuery click() Method The click event occurs when an element is clicked. The click() method triggers the click event, or attaches a function to run when a click event occurs.

Is there a click event in CSS?

Anyway, as of today, CSS doesn't provide any official way to handle a click event in CSS. But there are some very interesting tricks that we can use to “detect” a click using CSS only, without a single line of JavaScript, and this is what we are going to talk about today.


1 Answers

Reason the label's click handler is called twice:

Clicking on a label that is associated with an input causes two click events to be triggered. The first click event is triggered for the label. The default handling of that click event causes a second click event to get triggered for the associated input. Since you have the input as a descendant of the label, the second click event bubbles up to the label. That is why your click event handler is called twice.


If you really want to handle a click event for the label (and have it execute only once for a click):

(1) If you are willing and able to modify the HTML, you could move the input so it is not a descendant of the label. There will still be two click events, but the second click event will not bubble up from the input to the label since the label is no longer an ancestor of the input.

When the input is not a descendant of the label, you must use the label's "for" attribute to associated it with the input. The value of the "for" attribute should be the "id" value of the input. (You are already including the "for" attribute with the proper value.)

<input id="test_0" name="offering_cycle" type="checkbox" value="1">
<label for="test_0" class="">Fall</label>

(2) Preventing the default handling of the first click event prevents the second click event from getting triggered, BUT doing this breaks the label. That is, the checkbox will not get checked/unchecked when the label is clicked.

$('label[for*=test_]').on('click', function(event) {
    event.preventDefault();
    $(this).toggleClass('testing');
    // returning false would be another way to prevent the default handling.
});

jsfiddle


(3) Instead, you could stop the second click event from bubbling up from the input.

$('input:checkbox').on('click', function(event) {
    event.stopPropagation();
});

$('label[for*=test_]').on('click', function() {
    $(this).toggleClass('testing');
});

jsfiddle

Note: If the input was not a child of the label, this would not be necessary.


(4) Or you could check the event target in the handler. It will be the label for the first click event and the input for the second. The following handler executes the code inside the if-statement only for the first click event.

$('label[for*=test_]').on('click', function(event) {
    if (event.target == this) {
        $(this).toggleClass('testing');
    }
});

jsfiddle

Note: If the input was not a child of the label, the code above would still work, but the if-statement would be unnecessary because the click event triggered for the input would not bubble up to the label.


Handling the click for the input instead:

In your case, you don't really need to register a click handler for the label element. You could register a click (or change) handler for the input instead. You could then use $(this).closest('label') to get the label element.

$('input[name=offering_cycle]').on('click', function() {
     $(this).closest('label').toggleClass('testing');
});

jsfiddle

Note: If the input was not a child of the label, the handler above would still get called when you click on the label, but $(this).closest('label') would not get the label. You would have to use something like $('label[for="' + this.id + '"]') instead.


Regarding the "for" attribute on the label elements:

Since you have the inputs inside the labels, it is not necessary to include the for attributes on the labels --- but it's not invalid.

You have set the "for" attribute values to the values of the "id" attributes of the input elements. That is the correct way to use the "for" attribute to associated a label with an input. If you were to include a "for" attribute with an invalid value, the label would not be associated with the input, even if the input is a descendant of the label.

From the HTML5 spec for the "for" attribute of a label element:

The for attribute may be specified to indicate a form control with which the caption is to be associated. If the attribute is specified, the attribute's value must be the ID of a labelable element in the same Document as the label element. If the attribute is specified and there is an element in the Document whose ID is equal to the value of the for attribute, and the first such element is a labelable element, then that element is the label element's labeled control.

If the for attribute is not specified, but the label element has a labelable element descendant, then the first such descendant in tree order is the label element's labeled control.

like image 133
John S Avatar answered Oct 13 '22 03:10

John S