The reason the label tag handler is called twice:
Clicking on a label associated with input triggers two button press events. The first click event fires for the tag. The default processing of this click event triggers a second click event that will be triggered for the corresponding input. Since you have an input as a descendant of the label, the second click event bubbles up to the label. This is why your click event handler is called twice.
If you really want to handle the click event for a label (and execute it only once for a click):
(1) If you want and can change the HTML, you can move the input so that it is not a descendant of the label. There will still be two click events, but the second click event will not bubble from the entrance to the label, since the label is no longer the ancestor of the entrance.
When an input is not a descendant of a label, you must use the label attribute for the attribute associated with it. The value for the for attribute must be the id value for input. (You have already included the for attribute with the appropriate value.)
<input id="test_0" name="offering_cycle" type="checkbox" value="1"> <label for="test_0" class="">Fall</label>
(2) Preventing the default processing of the first click event prevents the second click event from triggering , but this violates the label . That is, the flag will not be checked / unchecked when the label is pressed.
$('label[for*=test_]').on('click', function(event) { event.preventDefault(); $(this).toggleClass('testing');
jsfiddle
(3) Instead, you can stop the second-click event from the bubbles 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 be optional.
(4) Or you can check the purpose of the event in the handler. This will be the label for the first click event and 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 will still work, but the if-statement will be unnecessary because the click event raised for input will not bubble up to the label.
Instead, click on the link:
In your case, you do not need to register a click handler for the label element. Instead, you can register a click (or change) handler for input. Then you can 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 will still be called when you click on the label, but $(this).closest('label') will not receive the label. Instead, you will need to use something like $('label[for="' + this.id + '"]') .
Regarding the "for" attribute of the label elements:
Since you have inputs inside labels, there is no need to include for attributes on labels --- but this is not invalid.
You set the "for" attribute values ββto the "id" attribute values ββfor the input elements. This is the correct way to use the "for" attribute to match the label with the input. If you must include the for attribute with an invalid value, the label will not be associated with the input, even if the input is a descendant of the label.
From the HTML5 specification for the attribute for the label element:
The for attribute can be specified to indicate the form control by which the label should be associated. If an attribute is specified, the attribute value must be the identifier of the element to be marked in the same document as the label element. If an attribute is specified and the document has an element whose identifier is equal to the value of the for attribute, and the first such element is a marked element, then this element is a label element with a label.
If the for attribute is not specified, but the label element has an inherited descendant element, then the first such descendant in the order tree is the label element marked with an icon.