How to check/uncheck radio button on click?
Solution 1:
This is not to replace a checkbox, it's to allow a radio group to go back to an unselected state. This was tricky because the radio selection doesn't act like a normal event.
The browser handles radio buttons outside the normal event chain. So, a click handler on a radiobutton with event.preventDefault() or event.stopPropagation() will NOT prevent the radiobutton from being checked. The .removeAttr('checked') must be done in a setTimeout to allow the event to finish, and the browser to check the radiobutton (again), and then the setTimeout will fire.
This also correctly handles the case where a user starts the mousedown but leaves the radiobutton before mouseup.
//$ = jQuery;
$(':radio').mousedown(function(e){
var $self = $(this);
if( $self.is(':checked') ){
var uncheck = function(){
setTimeout(function(){$self.removeAttr('checked');},0);
};
var unbind = function(){
$self.unbind('mouseup',up);
};
var up = function(){
uncheck();
unbind();
};
$self.bind('mouseup',up);
$self.one('mouseout', unbind);
}
});
I hope this helps
Solution 2:
try this:
$('input[type=radio]').click(function(){
if (this.previous) {
this.checked = false;
}
this.previous = this.checked;
});
Solution 3:
The accepted answer does not work on mobile devices. It relies on setTimeout and bindings that are related to mouse events that just don't fire on tablets/mobile devices.
My solution is to manually track the selected state using the "click" event handler and a custom class state.
- handle the click events on the radio input elements
- check if the "selected" class exists on the clicked element
- if it does, (meaning it has been clicked before), remove the class and uncheck the element, return
- if it doesn't, remove the class from all elements of the same name and add it to only the clicked element.
No need to prevent default behaviors. Here is the code in Jquery:
$("input:radio").on("click",function (e) {
var inp=$(this); //cache the selector
if (inp.is(".theone")) { //see if it has the selected class
inp.prop("checked",false).removeClass("theone");
return;
}
$("input:radio[name='"+inp.prop("name")+"'].theone").removeClass("theone");
inp.addClass("theone");
});
http://jsfiddle.net/bhzako65/
Solution 4:
I must be missing it but after all these years AFAIK none of the solutions above seem to work or maybe I'm just dumb.
There is absolutely no reason to use a radio button unless there is more than one radio button in the same group. If it's a lone radio button then just use a checkbox. The reason to use a radio button is for selecting one of mutually exclusive options. That means any solution which only looks at individual buttons will fail since clicking a one button will effect the state of the other buttons
In other words since we're using radioboxes the solution needs to work for
<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>
Here's one that looks at all the buttons.
This seems to work
document.querySelectorAll(
'input[type=radio][name=foo]').forEach((elem) => {
elem.addEventListener('click', allowUncheck);
// only needed if elem can be pre-checked
elem.previous = elem.checked;
});
function allowUncheck(e) {
if (this.previous) {
this.checked = false;
}
// need to update previous on all elements of this group
// (either that or store the id of the checked element)
document.querySelectorAll(
`input[type=radio][name=${this.name}]`).forEach((elem) => {
elem.previous = elem.checked;
});
}
body { font-size: xx-large; }
label, input {
/* added because a second click to unselect radio often
appears as a double click to select text */
-webkit-user-select: none;
user-select: none;
}
<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>
note if elem.previous
worries you you could use elem.dataset.previous
Another solution would be to store which button is checked
function makeRadioboxGroupUnCheckable(groupSelector) {
let currentId;
document.querySelectorAll(groupSelector).forEach((elem) => {
elem.addEventListener('click', allowUncheck);
// only needed if can be pre-checked
if (elem.checked) {
currentId = elem.id;
}
});
function allowUncheck(e) {
if (this.id === currentId) {
this.checked = false;
currentId = undefined;
} else {
currentId = this.id;
}
}
}
makeRadioboxGroupUnCheckable('input[type=radio][name=foo]');
body { font-size: xx-large; }
label, input {
/* added because a second click to unselect radio often
appears as a double click to select text */
-webkit-user-select: none;
user-select: none;
}
<input type="radio" name="foo" id="foo1"><label for="foo1">foo1</label>
<input type="radio" name="foo" id="foo2"><label for="foo2">foo2</label>
<input type="radio" name="foo" id="foo3"><label for="foo3">foo3</label>