Unselecting Radio Buttons with jQuery
I got a weird request from one of my internal customers today. In one of our applications he wanted to be able to "uncheck" radio buttons.
We all know that if you have a group of radio buttons, like this, that once you select one option, you cannot unselect an option, you can only change from one option to another.
<input type="radio" name="radio_group" />radio a<br />
<input type="radio" name="radio_group" />radio b<br />
<input type="radio" name="radio_group" />radio c<br />
Here is what I came up with.
UPDATE: The code below was provided in a comment from Jinxdone. It is much more elegant than my original code, so I am updating the entry to avoid having anyone use my code if they do not bother with the comments. Thanks Jinxdone!
<script type="text/javascript">
$(function(){
var allRadios = $('input[type=radio]')
var radioChecked;
var setCurrent =
function(e) {
var obj = e.target;
radioChecked = $(obj).attr('checked');
}
var setCheck =
function(e) {
if (e.type == 'keypress' && e.charCode != 32) {
return false;
}
var obj = e.target;
if (radioChecked) {
$(obj).attr('checked', false);
} else {
$(obj).attr('checked', true);
}
}
$.each(allRadios, function(i, val){
var label = $('label[for=' + $(this).attr("id") + ']');
$(this).bind('mousedown keydown', function(e){
setCurrent(e);
});
label.bind('mousedown keydown', function(e){
e.target = $('#' + $(this).attr("for"));
setCurrent(e);
});
$(this).bind('click', function(e){
setCheck(e);
});
});
});
</script>
So this is somewhat rudimentary quite elegant. , but it works. It has a few issues if you have JavaScript business logic that unchecks some of your radio buttons, because the click event doesn't happen then so the "checked" class does not get removed even though the radio button may have gotten unchecked. You would need to figure this out in your business logic or figure out a way to listen for that to happen and handle it. This solution also does not have the previous issues that mine had with other logic disabling, enabling and clearing other radio buttons.
UPDATE 7/8/2009: Thanks to comments from Tim and Jubal, I have added support for label element clicking and for keyboard input support.
Try it out here:
var radioChecked;
$('input[type=radio]').bind('mousedown', function() {
radioChecked = $(this).attr('checked');
});
$('input[type=radio]').bind('click', function() {
if (radioChecked) {
$(this).attr('checked', false);
} else {
$(this).attr('checked', true);
}
});
If you don't mind, I will update my post to reflect this more elegant solution (giving proper credit, of course).
Thanks for the input. I was just "arguing" the other day with some people about radio buttons and states. One argument, that I am not completely against, is that a radio group should never have an unchecked state. There should always be a default option that is checked. That way, instead of needing to uncheck it, you can simple check the default option.
In the case of the application I was working on, unchecking was easier than going back and adding default options to all of the radio groups.
I guess I don't really see a problem with doing it either way.
Minor nit: the code doesn't work for the label tag surrounding the radio input type. I can select the text within the label tags in order to select the radio button, but un-selecting requires clicking directly on the radio button, which isn't intuitive.
That's a good point. I'm going to look into that and see if i can address it easily.
$("label[for='" + $(this).attr('id') + "']").bind("mousedown", function(){
radioChecked = $("#"+ $(this).attr("htmlFor")).attr('checked');
});
});
This will do the trick for clicking the label
Thanks for your comments and for reinforcing the importance of proper accessibility. I have updated my code to now support the <label> tags and for keyboard input.
$("input[name='radioName']").attr('checked', false);
The rest of your example is tooling for allowing unselect via keypress etc. I have a separate event needing to unselect, so the key/mouse stuff is unneeded.
yeah, ok, thanks
So line
e.target = $('#' + $(this).attr("for"));
might became
e.target = $('#' + $(this).attr("for").replace(/(:|\.)/g,'\\$1'));
BTW: great script!
$(document).ready(function() {
$("input[type='radio']").mousedown(function(e) {
if ($(this).attr("checked") == true) {
setTimeout("$('input[id=" + $(this).attr('id') + "]').removeAttr('checked');", 200);}
else {
return true
}
});
});
I especially like that it functions transparently. All i needed to do was copy this code, drop it into my run-time code, and everything just works. Label-clicking, keyboard, everything. Everyone's done a fantastic job.
instead of attr('checked', false) you need to use removeProp('checked')
you saved my day. i used the code provided by jinxdone, Thanks jinxdone.
Works like a charm when you use the standard radio buttons, but I need to use whit radio buttons and jqueryUI, with the .buttonset() ...
any help? thanks in advance.
very good !!
It proves for very succinct code
A working example can be found here http://jsfiddle.net/KmBjJ/
mh
$( ".radio" ).click(function(){
var radioChecked;
$('input[type=radio]').bind('mousedown', function() {
radioChecked = $(this).prop('checked');
});
$('input[type=radio]').bind('click', function() {
if (radioChecked) {
$(this).prop('checked', false);
} else {
$(this).prop('checked', true);
}
});
$('input[type=radio]').each(function() {
$("label[for='" + $(this).attr('id') + "']").bind("mousedown", function(){
if (radioChecked) {
$('input[type=radio]').prop('checked', true);
} else {
$('input[type=radio]').prop('checked', false);
}
});
});
});
},500);
});
$(document).ready(function(){
inicial();
setTimeout(function(){
var makeRadiosDeselectableByName = function(name){
$('input[name=' + name + ']').click(function() {
if($(this).attr('previousValue') == 'true'){
$(this).prop('checked', false)
}
else
{
$('input[name=' + name + ']').attr('previousValue', false);
}
$(this).attr('previousValue', $(this).prop('checked'));
});
};
makeRadiosDeselectableByName('ensayo2811');
},500);
});
... SALUDOS DESDE CHILE