Trying to simulate label click
-
13-06-2021 - |
Question
Why doesn't this work? The label is inside the .item
parent. I don't want to put it outside of block elements as it wouldn't be valid.
So I'm trying to simulate a label click:
$(".item").click(function(){
$(this).find("label").click();
});
Edit: It's supposed to trigger the label and check a radio.
<script type="text/javascript">
$(document).ready(function () {
$(".item").click(function() {
$(this).find("label").click();
});
});
</script>
<div class="item">
<h4>Item</h4>
<ul>
<li>Description</li>
</ul>
<div class="radio-container">
<div class="radio-stack">
<input type="radio" class="styled" id="item1">
</div>
<label for="item1">$100</label>
</div>
</div>
Solution
Since this label is attached to some input (using the for
attribute), you could try something like:
var inputID = $(this).find("label").attr("for");
$('#' + inputID).click();
However you should be careful: since your input is inside the div with the .item
class, simulating a click in the radio will trigger your custom handler again, causing an infinite loop. If possible, just set the radio checked
attribute to true
instead of simulating a click:
$('#' + inputID).attr("checked",true);
(Working example at jsFiddle)
Otherwise, you'll need to find a way to exclude that radio from the .item
selector to avoid that infinite loop.
Update: after struggling a little with not
selectors, unsuccessfully, I came up with a quick and dirty hack: use a global (to the ready
closure) variable to control whether or not a simulated click is happening:
var updating = false;
$(".item").click(function() {
if ( !updating ) {
var inputID = $(this).find("label").attr("for");
updating = true;
$('#' + inputID).click();
updating = false;
}
});
Working example here. IMO Ayman Safadi's answer is better, but if you have trouble making it work cross-browsers this alternative could be used as a starting point.
OTHER TIPS
To strictly answer your question, it's not working because it's causing an infinite loop of "clicks", and your browser just kills the event silently.
Run this demo, and look at your JS console: http://jsfiddle.net/bRyR3/
The div
is capturing the label
click event. In other words, JavaScript interprets your logic like this:
When you click on
.item
, trigger thelabel
"click
" event.
label
is inside.item
, therefore iflabel
is clicked, so is.item
.When you click on
.item
, trigger thelabel
"click
" event.
label
is inside.item
, therefore iflabel
is clicked, so is.item
.When you click on
.item
, trigger thelabel
"click
" event.
label
is inside.item
, therefore iflabel
is clicked, so is.item
.etc...
Working on actual solution.
Solution
$('.item').on('click', function(e) {
console.log('click');
$('label', $(this)).trigger('click');
});
$('.item label').on('click', function(e) {
e.stopPropagation();
});
This will stop .item
from capturing label
's click
event.
Working demo: http://jsfiddle.net/bRyR3/1/
Since this question & answer pops up when looking for a solution, there is a third way to solve this issue:
JQuery allows for custom parameters to be sent to the on() event handlers, by using trigger()
See https://api.jquery.com/trigger/
This means, it's possible to avoid an endless loop by simply telling the event handler that the current event is 'artificial':
$( document ).on( 'click touch', '.item', function( event, artificial ) {
if( artificial ) return;
$(this).find("label").trigger( 'click', [ true ] );
} );
This has the advantage of not stopping propagation (or relying on it), while also not fumbling around with different input types (checkboxes, radios, texts, etc). It just simulates a click on the label without any additional work on our side or any endless loops.