21

I have group checkboxes and I like if this group have behaviour like radiobuttons with same name atribute.

Each checkbox has different name.

Only one can be chosen from checkboxes.

How I can do this?


Solution

Why I need this? Because we need consistency webUI. Please, this is not question about our application architecture. :)

HTML Sample

<div class="multiCheckBox">
 <span class="multiGroup">
  <div><input class="multiItem" value="111" name="list" type="checkbox" />111</div>
  <div><input class="multiItem" value="112" name="list" type="checkbox" />112</div>
  <div><input class="multiItem" value="113" name="list" type="checkbox" />113</div>
 </span>
 <span>
  <div><input class="multiItem" value="121" name="list" type="checkbox" />121</div>
  <div><input class="multiItem" value="122" name="list" type="checkbox" />122</div>
  <div><input class="multiItem" value="133" name="list" type="checkbox" />123</div>
 </span>
 <span>
  <div><input class="multiItem" value="131" name="list" type="checkbox" />131</div>
  <div><input class="multiItem" value="132" name="list" type="checkbox" />132</div>
  <div><input class="multiItem" value="133" name="list" type="checkbox" />133</div>
 </span>
</div>

JavaScript

var $groups = $("span.multiGroup", $that);
$groups.each(function() {
    var $group = $(this);
    var $checkboxes = $(":checkbox", $group);
    $checkboxes.click(function() {
        var $activeCheckbox = $(this);
        var state = $activeCheckbox.attr('checked');
        $checkboxes.attr('checked', false);
        $activeCheckbox.attr('checked', state);
    });
});
MicTech
  • 42,457
  • 14
  • 62
  • 79
  • 2
    Why not use radio buttons? Oh, and you might want to put the code of your attempt to do it, so we know what you're looking for... – Shalom Craimer May 19 '09 at 06:12
  • 2
    Don't use check boxes for radio buttons. Use radio buttons for radio buttons. Would you use a light switch on your door instead of a doorknob? – Tim Sullivan May 20 '09 at 18:51
  • 2
    Tim: Thanks for you opinion, but this is best way how I do what I need. And this question about webUI, not about my application architecture. – MicTech May 20 '09 at 18:57
  • 4
    For my form, I need the user to be able to deselect a "radio" option so I have to use checkboxes but only one checkbox can be selected if a checkbox is checked. – HPWD Nov 01 '12 at 19:52
  • Their are some great answers here but I found this question was more suited to the behavior I needed: http://stackoverflow.com/questions/2117538/jquery-how-to-uncheck-a-radio-button – HPWD Nov 01 '12 at 20:01

9 Answers9

66

Here's a hint: Use radio buttons. ;)

I wouldn't recommend doing this because it would be considered bad for usability and would certainly violate the principle of least surprise. Users have been conditioned to expect radios to accept 1 check and checkboxes to accept many. Don't make your users think.

If you have your reasons, though, here's how to go about doing this with jQuery:

<input type='checkbox' name='mygroup1' value='1' class='unique'>
<input type='checkbox' name='mygroup2' value='2' class='unique'>
<input type='checkbox' name='mygroup3' value='3' class='unique'>

And the jQuery:

var $unique = $('input.unique');
$unique.click(function() {
    $unique.filter(':checked').not(this).removeAttr('checked');
});

And here's a live sample.

EDIT:

As pointed out in the comments, this would allow the user to deselect all checkboxes even if they chose one initially, which isn't exactly like radio buttons. If you want this, then the jQuery would look like this:

var $unique = $('input.unique');
$unique.click(function() {
    $unique.removeAttr('checked');
    $(this).attr('checked', true);
});
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
  • Each checkbox has different name. – MicTech May 19 '09 at 06:11
  • @MicTech: I think that even if they all have different names, you should make the inputs to be radio-buttons - that way the user really won't be surprised when they act like radio-buttons, eh? – Shalom Craimer May 19 '09 at 06:14
  • 1
    Very elegant solution and nice answer. Your code allows all checkboxes to be unchecked. This isn't "radiobutton" functionality. It depends however on what the user wants. – kgiannakakis May 19 '09 at 06:19
  • My use case is that a case/switch would toggle between if they can select more than one or not. Otherwise they can any amount of them. Do you feel this is still unjustified and that I should hide/show an alternative radio form list? – Trip Jul 30 '12 at 14:44
  • 1
    @Trip: I think that would probably be an acceptable use case, I don't love it but it is what it is. – Paolo Bergantino Jul 30 '12 at 17:13
6

Why don't you use radio buttons, then?

The difference is there for a reason. It has been designed this way, and from a user perspective radio buttons mean "select one", and checkboxes mean "select many".

Don't break user's expectations by changing this well-tried paradigm. It's a bad thing when application developers prefer "looks" over usability and convention, so don't be one of them.

User interfaces work because the metaphors used (checkboxes, buttons, the shape of the mouse pointer, colors, etc.) are and behave a certain way. Users will have problems with your app and may not even know why when you do things like this.

This is an anti-pattern that falls into the same category as changing the label with the checkbox state:

[ ] enable option        vs.      [ ] option
[x] disable option                [x] option
Tomalak
  • 332,285
  • 67
  • 532
  • 628
2

I had a similar problem. I couldn't use radio button because the same form had to display multiple choice checkboxes in some situations. I took your markup and wrote this small piece of jQuery:

$("span.multiGroup input").click(function() {
    $("span.multiGroup input").attr('checked', false);
    $(this).attr('checked', true);
});
cspolton
  • 4,495
  • 4
  • 26
  • 34
1
var $unique = $('input.unique');

$unique.click(function() {

 $checked = $(this).is(':checked') ; // check if that was clicked.
 $unique.removeAttr('checked'); //clear all checkboxes
 $(this).attr('checked', $checked); // update that was clicked.

});
user2050723
  • 71
  • 1
  • 3
1
$(".checkboxClass").click(function() {
    $(".checkboxClass").each(function() {
        $(this)[0].checked = false;});
    $(this)[0].checked = true;
});

First clear all checkboxes, then check the one that was clicked.

kgiannakakis
  • 103,016
  • 27
  • 158
  • 194
0

HTML

<input type='checkbox' name='mygroup1' value='1' class='unique'>
<input type='checkbox' name='mygroup2' value='2' class='unique'>
<input type='checkbox' name='mygroup3' value='3' class='unique'>

Javascript

$('input.unique').each(function() {
    $(this).on('touchstart click', function() {
    $('input.unique').not(this).removeAttr('checked');
});
});

Fiddle: http://jsfiddle.net/L2ad1vd8/

0

Pablo's answer works great if you only have one set of these on your page. I came across this when attempting to workaround a bootstrap implementation that was giving me some trouble because radio buttons had been completely overwritten and it turns out it will be easier to just use the checkboxes as radio buttons.

Here's a version of this code that allows multiple sets by referencing the calling element's second class.

$('input.unique').each(function() {
  $(this).on('touchstart click', function() {
    var secondClass = $(event.target).attr('class').split(' ')[1];
    $('input.' + secondClass).not(this).removeAttr('checked');
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type='checkbox' name='mygroup1' value='1' class='unique check1'>
<input type='checkbox' name='mygroup2' value='2' class='unique check1'>
<input type='checkbox' name='mygroup3' value='3' class='unique check1'>
<br>
<hr>
<input type='checkbox' name='mygroup1' value='1' class='unique check2'>
<input type='checkbox' name='mygroup2' value='2' class='unique check2'>
<input type='checkbox' name='mygroup3' value='3' class='unique check2'>

JSFiddle

Jonathan Lucas
  • 545
  • 1
  • 4
  • 6
0

This live demo illustrates Radio Button can perform what you desired:

http://jsfiddle.net/ftnwg8yf/

function selectiongrp_control( s_selectiongrpName, b_useJQueryUiThemeToDecorate )
{
 var ADF_THIS_IS_LAST_SELECTED_ATTR='adf_this-is-last-selected-attr'
 var ADF_THIS_IS_LAST_SELECTED_VALUE='adf_this-is-last-selected-val';

 if ( !s_selectiongrpName ) return -1;

 $( '#fieldset-' + s_selectiongrpName + '-result' ).hide();
 if( b_useJQueryUiThemeToDecorate )   $( '#jQueryUi-' + s_selectiongrpName).buttonset();

 $( 'input[name=' + s_selectiongrpName + ']' ).each( function()
 {
  $( this ).on( 'click', function()
  {
   if( $( this ).attr( ADF_THIS_IS_LAST_SELECTED_ATTR ) )
   {
    $( this ).removeAttr( 'checked' );
    $( this ).removeAttr( ADF_THIS_IS_LAST_SELECTED_ATTR );
   } else
   {
    $( this ).attr( ADF_THIS_IS_LAST_SELECTED_ATTR, ADF_THIS_IS_LAST_SELECTED_VALUE );
   }

   $( 'input[name=' + s_selectiongrpName + ']' ).not( this ).removeAttr( ADF_THIS_IS_LAST_SELECTED_ATTR );
   if( b_useJQueryUiThemeToDecorate )   $( '#jQueryUi-' + s_selectiongrpName ).buttonset( 'refresh' );

   if( $( 'input[name=' + s_selectiongrpName + ']:checked' ).length > 0 )
   {
    $( '#fieldset-' + s_selectiongrpName + '-resultarea' ).html( 'You have selected : [' + $( this ).val() + '].');
   } else
   {
    $( '#fieldset-' + s_selectiongrpName + '-resultarea' ).html( 'Nothing is selected.' );
   }
   $( '#fieldset-' + s_selectiongrpName + '-result' ).show();
  });
 });
}

$( document ).ready( function() {
 var ADF_USE_JQUERYUI_THEME_TO_DECORATE=true;
 selectiongrp_control( 'selectiongrp-01', !ADF_USE_JQUERYUI_THEME_TO_DECORATE );
 selectiongrp_control( 'selectiongrp-02', ADF_USE_JQUERYUI_THEME_TO_DECORATE );
});
<!-- Load jQuery core library -->
<script type='text/javascript' src='http://code.jquery.com/jquery-2.1.4.min.js'></script>

<!-- Load jQueryUI library-->
<script type='text/javascript' src='http://code.jquery.com/ui/1.11.4/jquery-ui.js'></script>

<!-- Load jQueryUI Theme library (make either one effective) -->
<!--
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/ui-darkness/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/blitzer/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/eggplant/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/flick/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css'>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/sunny/jquery-ui.css'>
-->
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/redmond/jquery-ui.css'>



<h3>Plain (without styling/decoration):</h3>
<fieldset id='fieldset-selectiongrp-01'>
 <legend>Please <b>click</b> to <b>select</b> or <b>re-click</b> to <b>deselect</b> </legend>
 <span id='jQueryUi-selectiongrp-01'>
  <input type='radio' name='selectiongrp-01' value='Yes' id='selectiongrp-01-option-Y'/><label for='selectiongrp-01-option-Y'>Yes</label>
  <input type='radio' name='selectiongrp-01' value='No' id='selectiongrp-01-option-N'/><label for='selectiongrp-01-option-N'>No</label>
  <input type='radio' name='selectiongrp-01' value='Unknown' id='selectiongrp-01-option-U' /><label for='selectiongrp-01-option-U'>Unknown</label>
 </span>
</fieldset>
<fieldset id='fieldset-selectiongrp-01-result'>
 <legend>Result</legend>
 <span id='fieldset-selectiongrp-01-resultarea'></span>
</fieldset>

<br/>

<h3>Decorated by &quot;jQueryUI Theme&quot;:</h3>
<fieldset id='fieldset-selectiongrp-02'>
 <legend>Please <b>click</b> to <b>select</b> or <b>re-click</b> to <b>deselect</b> </legend>
 <span id='jQueryUi-selectiongrp-02'>
  <input type='radio' name='selectiongrp-02' value='Yes' id='selectiongrp-02-option-Y'/><label for='selectiongrp-02-option-Y'>Yes</label>
  <input type='radio' name='selectiongrp-02' value='No' id='selectiongrp-02-option-N'/><label for='selectiongrp-02-option-N'>No</label>
  <input type='radio' name='selectiongrp-02' value='Unknown' id='selectiongrp-02-option-U' /><label for='selectiongrp-02-option-U'>Unknown</label>
 </span>
</fieldset>
<fieldset id='fieldset-selectiongrp-02-result'>
 <legend>Result</legend>
 <span id='fieldset-selectiongrp-02-resultarea'></span>
</fieldset>
  • That seems like quite a lot of code. Would you mind explaining the benefit of it -- how does it address the original question better than the existing answers? – RJHunter May 06 '15 at 10:42
0

Based on the primitive behaviour of "radio buttons group" that only one radio button can be selected within the same group, "radio buttons approach" is always preferred than "checkboxes approach", because it can help preventing anomalous data submission in the event of JavaScript or jQuery coding cannot be loaded properly.

Then, the only challenge for us to solve is to make the selected radio button be 'de-selectable'.

So, here is an example to show that, by using additional JavaScript control, radio buttons still can be de-selected. This example has used jQuery as the main JavaScript framework.

Online version is also available in JSFiddle.net: http://jsfiddle.net/0fbef3up/

This example has considered to cater for a contingency scenario in case JavaScript or jQuery coding does not load, and so a 'contingent option item' is provided. In order to see how will be such special scenario and how does the contingency work, you can simply omit the loading of the jQuery library by comment/delete the relevant line of code:

<script type='text/javascript' src='http://code.jquery.com/jquery-2.1.4.min.js'></script>

Below is the full HTML/JavaScript code for demonstration. The essence is at the JavaScript function 'selectiongrp_logicControl', you may study it for reference.

JavaScript (i.e., control/model layer) at the first coding frame and HTML (i.e. presentation layer) at the second coding frame:

function selectiongrp_logicControl( s_selectiongrpName, b_useJQueryUiThemeToDecorate )
{
 // Safeguard measure: If the mandatory function parameter is undefined or empty, nothing can be proceed further, so quit the current function with excit code:
 if ( !s_selectiongrpName ) return -1;


 // Define a constant for future use:
 var ADF_THIS_IS_LAST_SELECTED='adf_this-is-last-selected';

 // Hide the 'contingent select option item' and all its relevant ancillary objects (i.e. the label element):
 $( '#' + s_selectiongrpName + '-option-X' ).hide();
 $( '#' + s_selectiongrpName + '-option-X' ).next( 'label' ).hide();

 // Decorate the selection group option items and their labels by applying the jQueryUI 'buttonset' function:
 if( b_useJQueryUiThemeToDecorate )   $( '#jQueryUi-' + s_selectiongrpName).buttonset();

 // Loop for each option item within the selection group:
 $( 'input[name=' + s_selectiongrpName + ']' ).each( function()
 {
  // Define an 'onClick' event for every option item within the selection group:
  $( this ).on( 'click', function()
  {
   // If the option item being clicked is the last selected one, then de-select such item.
   // Two ways can achieve de-selection, apply either one below to adapt to your programming style or desired controller mechanism.

   if( $( this ).attr( ADF_THIS_IS_LAST_SELECTED ) )
   {
    // Way[1]: Force selecting another item within the same selection group.
    // This Way entails the 'contingent select option item'.  So, if you consider such 'contingent select option item' is unnecessary/inappropriate to your programming style or controller mechanism, please don't choose this Way.
    // (Note: Such 'contingent select option item' was deliberately hidden at the outset).
    // $( '#' + s_selectiongrpName + '-option-X' ).prop( 'checked', true );

    // Way[2]: Simply remove the current item's "checked" attribute:
    $( this ).removeAttr( 'checked' );

    // Both Way[1] and Way[2]: Remove the additional attribute from the item being clicked.
    $( this ).removeAttr( ADF_THIS_IS_LAST_SELECTED );
   } else
   {
    // Apply an additional attribute to the item being clicked.  This additional attribe functioned as a secret hint for internal reference to signify the item was the last seledcted one:
    $( this ).attr( ADF_THIS_IS_LAST_SELECTED, ADF_THIS_IS_LAST_SELECTED );
   }
   // Other than the item being clicked, all other items (i.e. denotes by the jQuery 'not( this )' selector) should have removed such additional attribute:
   $( 'input[name=' + s_selectiongrpName + ']' ).not( this ).removeAttr( ADF_THIS_IS_LAST_SELECTED );

   // Force the jQueryUI engine to re-render the decoration to reflect the latest selection by applying the 'buttonset' function again ( provide the 'refresh' parameter ):
   if( b_useJQueryUiThemeToDecorate )   $( '#jQueryUi-' + s_selectiongrpName ).buttonset( 'refresh' );

   // Lastly, this is an optional step, refresh the Result Area for displaying user's latest selection on specific screen area:
   selectiongrp_visualControl_refreshResultArea( s_selectiongrpName );
  });
 });
}



function selectiongrp_visualControl_refreshResultArea( s_selectiongrpName )
{
 // Safeguard measure: If the mandatory function parameter is undefined or empty, nothing can be proceed further, so quit the current function with excit code:
 if( !s_selectiongrpName )   return -1;


 var adf_resultArea_string;
 var ADF_RESULTAREA_STRING_NOTHING_SELECTED='Nothing is selected';

 // If Way[1] is adopted:
 if( $( '#' + s_selectiongrpName + '-option-X' ).prop( 'checked' ) )
 {
  adf_resultArea_string=ADF_RESULTAREA_STRING_NOTHING_SELECTED;
 } else // If Way[2] is adopted:
 {
  // If some option items are selected within the selection group:
  if( $( 'input[name=' + s_selectiongrpName + ']:checked' ).length > 0 )
  {
   adf_resultArea_string='You have selected : [' + $( 'input[name=' + s_selectiongrpName + ']:checked' ).next( 'label' ).text() + ']';
  } else
  {
   adf_resultArea_string=ADF_RESULTAREA_STRING_NOTHING_SELECTED;
  }
 }

 $( '#fieldset-' + s_selectiongrpName + '-resultarea' ).html( adf_resultArea_string );
 $( '#fieldset-' + s_selectiongrpName + '-result' ).show();
}

$( document ).ready( function()
{
 var ADF_USE_JQUERYUI_THEME_TO_DECORATE=true;
 selectiongrp_logicControl( 'selectiongrp-01', !ADF_USE_JQUERYUI_THEME_TO_DECORATE );
 selectiongrp_logicControl( 'selectiongrp-02', ADF_USE_JQUERYUI_THEME_TO_DECORATE );

 // If jQuery can be loaded properly, the error message must be hidden:
 $( '#jquery-compatibility-error' ).hide();
});
<!-- Load jQuery core library -->
<script type='text/javascript' src='http://code.jquery.com/jquery-2.1.4.min.js'></script>

<!-- Load jQueryUI library -->
<script type='text/javascript' src='http://code.jquery.com/ui/1.11.4/jquery-ui.min.js'></script>

<!-- Load jQueryUI Theme library (make either one effective) -->
<!--
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/ui-darkness/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/blitzer/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/eggplant/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/flick/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.min.css'/>
<link rel="stylesheet" type="text/css" href='http://code.jquery.com/ui/1.11.4/themes/sunny/jquery-ui.min.css'/>
-->
<link rel='stylesheet' type='text/css' href='http://code.jquery.com/ui/1.11.4/themes/redmond/jquery-ui.min.css'>


This webpage is primarily to demonstrate de-selectable radio boxes.

<h3 id='jquery-compatibility-error'>ERROR: It was detected that JavaScript or jQuery coding does not load properly, so some advance feature cannot be realised.</h3>

<h3>Style1: Raw (i.e. no styling/decoration):</h3>
<fieldset id='fieldset-selectiongrp-01'>
 <legend>Please <b>click</b> to <b>select</b> or <b>re-click</b> to <b>deselect</b></legend>
 <span id='jQueryUi-selectiongrp-01'>
  <input type='radio' name='selectiongrp-01' value='X' id='selectiongrp-01-option-X' checked/><label for='selectiongrp-01-option-X'>None/NULL/Non-Selected <small><small>(This option is provided for contingency purpose in case JavaScript or jQuery does not load)</small></small></label>
  <input type='radio' name='selectiongrp-01' value='Y' id='selectiongrp-01-option-Y'/><label for='selectiongrp-01-option-Y'>Yes</label>
  <input type='radio' name='selectiongrp-01' value='N' id='selectiongrp-01-option-N'/><label for='selectiongrp-01-option-N'>No</label>
  <input type='radio' name='selectiongrp-01' value='U' id='selectiongrp-01-option-U' /><label for='selectiongrp-01-option-U'>Unknown</label>
 </span>
</fieldset>
<fieldset id='fieldset-selectiongrp-01-result' style='display:none'>  <!-- Initaially hidden by using stylesheet attribute "style='display:none'"-->
 <legend>Selection</legend>
 <span id='fieldset-selectiongrp-01-resultarea'><br/></span>
</fieldset>

<br/>

<h3>Style2: Decorated by &quot;jQueryUI Theme&quot; <small><small>(jQueryUI Theme adopted: '<i>Redmond</i>')</small></small>:</h3>
<fieldset id='fieldset-selectiongrp-02'>
 <legend>Please <b>click</b> to <b>select</b> or <b>re-click</b> to <b>deselect</b></legend>
 <span id='jQueryUi-selectiongrp-02'>
  <input type='radio' name='selectiongrp-02' value='X' id='selectiongrp-02-option-X' checked/><label for='selectiongrp-02-option-X'>None/NULL/Non-Selected <small><small>(This option is provided for contingency purpose in case JavaScript or jQuery does not load)</small></small></label>
  <input type='radio' name='selectiongrp-02' value='Y' id='selectiongrp-02-option-Y'/><label for='selectiongrp-02-option-Y'>Yes</label>
  <input type='radio' name='selectiongrp-02' value='N' id='selectiongrp-02-option-N'/><label for='selectiongrp-02-option-N'>No</label>
  <input type='radio' name='selectiongrp-02' value='U' id='selectiongrp-02-option-U' /><label for='selectiongrp-02-option-U'>Unknown</label>
 </span>
</fieldset>
<fieldset id='fieldset-selectiongrp-02-result'style='display:none;'>  <!-- Initaially hidden by using stylesheet attribute "style='display:none'"-->
 <legend>Selection</legend>
 <span id='fieldset-selectiongrp-02-resultarea'><br/></span>
</fieldset>
kman
  • 1
  • 1