5


I am trying to run some function when clicking on the label text but the click event fired two times.
HTML

<label class="label_one">
    Label One
    <input type="checkbox"/>
</label>

But its not happening if I change the html code like this.

<label for="test" class="label_two">
    Label Two
    <input type="checkbox"/>
</label>

My script is this:

$('.label_one').click(function(){
    console.log('testing');
});

Can anyone explain me why this is happening like this.
My jsfiddle is here check it ones.
https://jsfiddle.net/sureshpattu/hvv6ucu8/3/

Suresh Pattu
  • 6,083
  • 16
  • 59
  • 91

5 Answers5

5

It is because of event bubbling.

In general all elements bubble the event to the root of the document whereas the label tag will bubble the event to its child nodes and thats how the input tag is getting ticked when you click the label dom.

So in your case you attached the event handler to label tag so

  1. It calls when label tag gets clicked
  2. event bubbles inside it and checkbox gets selected and checkbox bubbles the event to its parent node that is label tag again hence it is called twice.

To solve this, just attach the event handler to input/checkbox tag it should work fine.

Community
  • 1
  • 1
rajuGT
  • 6,224
  • 2
  • 26
  • 44
  • 1
    An event doesn't bubble to its children – A. Wolff Oct 30 '15 at 11:00
  • @A.Wolff I couldnt find official document for that, I'll try for it. May be its not purely bubbling but I can show you with proof that event object is going to input tag. https://jsfiddle.net/hvv6ucu8/7/ check this fiddle. you can test by uncommenting alert statement for more information. Once I find official resource I'll update my answer with correction according to the specs/doc. – rajuGT Oct 30 '15 at 11:33
  • In fact what i meant is that event doesn't bubble to checkbox but fires a synthetic click on it if the clicked the label wrapping it. `For example, on platforms where clicking a checkbox label checks the checkbox, clicking the label in the following snippet could trigger the user agent to run synthetic click activation steps on the input element, as if the element itself had been triggered by the user` http://www.w3.org/TR/html5/forms.html#labeled-control Then once the synthetic click event is done, this event bubbles to its parent, meaning the label – A. Wolff Oct 30 '15 at 11:41
  • 1
    So indeed your answer is not wrong but the main reason of this behaviour is browser behaviour regarding `labeled control.` An event always bubbles/propagates from descendant to ascendant elements. The capture phase is the opposite – A. Wolff Oct 30 '15 at 11:44
3

I couldn't reproduce this in the version of chrome that I'm using.

But if you're facing this in some browser, it's likely because -

According to spec, labels containing inputs, and the ones connected to an input via for attribute trigger a click on the associated input when they are clicked.

So in your first case, there are 2 click events:

  • Actual click on <label>
  • Click triggered on <input> by the label

The one triggered on <input> will bubble up to <label> and trigger your handler.

In the second case, Since a for attribute is specified and there is no matching input with id of 'test', the additional click is not triggered even if the input is inside the label.

T J
  • 42,762
  • 13
  • 83
  • 138
  • 1
    `I couldn't reproduce this in the version of chrome that I'm using` Which version/OS are you testing it? Because all chrome version should follow sepc regarding this behaviour – A. Wolff Oct 30 '15 at 11:10
  • @A.Wolff chrome 46~ for windows , I tried the fiddle he shared and clicking both inputs only adds one log thingy... – T J Oct 30 '15 at 11:36
  • Same chrome vs here on win7, the expected behaviour (issue) is fired. Maybe related to your OS but i would be really surprised. Maybe that's a bug then :) – A. Wolff Oct 30 '15 at 11:39
2

Click on checkbox do click on label. Try use .change event on input

$('.label_one input').change(function(){
    var html = '<div class="log_sec_one">Log</div>';
    $('.logs').append(html);
});

$('.label_two input').change(function(){
    var html = '<div class="log_sec_two">Log</div>';
    $('.logs').append(html);
});

DEMO

Anon
  • 2,854
  • 14
  • 18
0

Move your input outside of your label, and use the for="" attribute.

<label class="label_one" for="checkbox_one">
    Label One
</label>
<input type="checkbox" id="checkbox_one" />
<br/><br/>
<label for="checkbox_two" class="label_two">
    Label Two
</label>
<input type="checkbox" id="checkbox_two"/>

<div class="logs"></div>

JSFiddle: https://jsfiddle.net/hvv6ucu8/2/

L Ja
  • 1,384
  • 1
  • 11
  • 22
0
<label for="text" class="label_one">
    Label One
    <input type="checkbox"/>
</label>
<br/><br/>
<label for="text" class="label_two">
    Label Two
    <input type="checkbox" name="1"/>
</label>

you forgot to put for attribute in label (label_one). just change that. it will work