11

I've seen many check/uncheck all checkboxes scripts. But far most does not respect that if I toggled all checkboxes using the "checked all"-checkbox and then uncheck a single one in the list, the "checked all" checkbox is still checked.

Is there an elegant way of handling this case?

janhartmann
  • 14,713
  • 15
  • 82
  • 138
  • 3
    From a UI point of view you probably want a [three state checkbox](http://stackoverflow.com/questions/1726096/tri-state-check-box-in-html) so you can show the some-on-some-off case as something else. But you have to fake these in HTML, or <5 at least. I've used a good implementation before but it's not one of the answers in that question - can't remember where though. [The first example there](http://shamsmi.blogspot.com/2008/12/tri-state-checkbox-using-javascript.html) can do this out of the box, although not in jQuery, and using separate images for each state rather than one + CSS. – Rup Jan 26 '11 at 13:35
  • 2
    Another alternative example: http://jsfiddle.net/Raynos/mSFts/ – Raynos Jan 26 '11 at 13:37
  • @Raynos: Nice, but it doesn't check "check all" when manually checking all checkboxes. – ThiefMaster Jan 26 '11 at 13:39
  • Never thought of three state checkbox. Intersting. :-) – janhartmann Jan 26 '11 at 13:39
  • @ThiefMaster that wasn't requested. – Raynos Jan 26 '11 at 14:35

4 Answers4

14
$('#checkAll').click(function() {
    if(this.checked) {
        $('input:checkbox').attr('checked', true);
    }
    else {
        $('input:checkbox').removeAttr('checked');
    }
});

$('input:checkbox:not(#checkAll)').click(function() {
    if(!this.checked) {
        $('#checkAll').removeAttr('checked');
    }
    else {
        var numChecked = $('input:checkbox:checked:not(#checkAll)').length;
        var numTotal = $('input:checkbox:not(#checkAll)').length;
        if(numTotal == numChecked) {
            $('#checkAll').attr('checked', true);
        }
    }
});

Demo: http://jsfiddle.net/ThiefMaster/HuM4Q/

As pointed out in the question's comment, a regular checkbox is not perfect for this. My implementation disables the "check all" box as soon as one checkbox is unchecked. So, to uncheck all still-checked checkboxes you'll have to click twice (first to re-check the unchecked ones and then to uncheck all other ones). However, with a tri-state checkbox this might still be necessary as the state order might be unchecked->indefinite->checked->unchecked, so you'd need two clicks to come from indefinite to unchecked.


Since you probably don't want to check ALL checkboxes on your page with "Check All", replace input:checkbox with e.g. .autoCheckBox or input.autoCheckBox:checkbox and give those checkboxes class="autoCheckBox".

If you want all checkboxes inside a certain form, simple use #idOfYourForm input:checkbox or form[name=nameOfYourForm] input:checkbox

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
2

You can achieve this by attaching a click handler to each of the target checkboxes, and have that handler un-check the "control" checkbox based on the collective state of those target checkboxes. So, something like this:

// Control checks/unchecks targets
$('#controlcheckbox').click( function(){
  $('.targetcheckboxes').attr('checked', this.checked );
});

// Targets affect control
$('.targetcheckboxes').click( function(){
  if( $('.targetcheckboxes:not(:checked)').length ){
    $('#controlcheckbox').attr('checked',false);
  }
});

Even better -- you could attach this logic to an enclosing container element, and watch for the event using .delegate():

$('#some_container').delegate('.targetcheckboxes','click',function(){...} );
Ken Redler
  • 23,863
  • 8
  • 57
  • 69
1
$("#selectall").click(function(){
    var checked = $("#selectall").attr("checked");
    $(".selectone").attr("checked",checked);
});

For setting select all

 $(".selectone").click(function(){
   var net = $(".selectone").map(function(){ return jQuery(this).attr("checked");}).get();
   var flg = true;
   if(jQuery.inArray(false, net)){
     flg= false;
   }
   $("#selectall").attr("checked",flg);
 });
Harish
  • 2,311
  • 4
  • 23
  • 28
0

Perhaps something like this:

$('tbody input:checkbox').change(function(){
    if ($(this).closest('tbody').find('input:checkbox').not(':checked').length) {
        $('#checkAll')[0].checked = false;
    }
});

This assumes that #checkAll is in the thead section of your table.

lonesomeday
  • 233,373
  • 50
  • 316
  • 318