I'm trying to find out whether a checkbox ids cheked o not after a user has clicked it. The checkbox is wrapped in a label which must be clickable too. My HTML code is:
<div id="view_container">a</div>
<script type="text/template" id="view_template">
<ul>
<li>
<label>
<input type="checkbox" checked="" value="a">A option
</label>
</li>
<li>
<label>
<input type="checkbox" value="b">B option
</label>
</li>
<li>
<label>
<input type="checkbox" value="c">C option
</label>
</li>
</ul>
</script>
Ans the JavaScript:
View = Backbone.View.extend({
initialize: function() {
console.log('in the init');
this.render();
},
render: function() {
var template = _.template($("#view_template").html(), {});
this.el.html(template);
},
events: {
'click ul li label': 'clicked',
},
clicked: function(e) {
e.stopPropagation();
console.log('e.target is ' + e.target);
console.log('e.currentTarget is ' + e.currentTarget);
var isChecked = $(e.currentTarget).find('input:first').is(':checked');
var selected = $(e.currentTarget).find('input:first').val().trim();
console.log('isChecked is ' + isChecked);
},
});
var view = new View({
el: $("#view_container")
});
The jsfiddle is here.
There are a few problems. If i click the input, it works fine and the value of isChecked
is true. However, if i clicked the label, the function clicked
is executed twice with console.log
output of:
e.target is [object HTMLLabelElement]
e.currentTarget is [object HTMLLabelElement]
isChecked is false
e.target is [object HTMLInputElement]
e.currentTarget is [object HTMLLabelElement]
isChecked is true
So isChecked
is false the first time.
So, how do I know if the checkbox is being checked or not, regardless of if user clicks on label or directly on the input? And how do I stop handler from executing twice when user clicks on label?
The issue is that, by nature, the labels containing <input>
s or connected to them via for
attribute triggers a click event on the associated input. So there are 2 click events:
<label>
<input>
by the label.So if we listen to click events on label, we will catch both of them in this case - because the click triggered on <input>
will also bubble up to <label>
since it's a parent.
We can solve this by listening to clicks on the checkbox itself, rather than the label.
You can do the following using jQuery is
method with :checkbox
and :checked
selectors as shown below.
View = Backbone.View.extend({
initialize: function () {
this.render();
},
template: _.template($("#view_template").html()),
events: {
'click ul li :checkbox': 'clicked',
},
render: function () {
this.$el.append(this.template({}));
},
clicked: function (e) {
var $target = $(e.target);
var selected = $target .is(':checked');
console.log('selected: ', selected, 'value: ', $target.val());
}
});
var view = new View({
el: $("#view_container")
});
Updated fiddle
Note that it's a good practice to cache the template function rather than calling _template
each time render is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With