1

I have a jQuery script that has multiple checkbox groups. If the 'Parent' is selected, it should also select all the 'Child' boxes and if any 'Child' boxes are unselected, then the 'Parent' should also be unselected and only the selected 'Child' boxes left checked.

Here is a jsFiddle: http://jsfiddle.net/9NmE7/

The problem is that with jQuery 1.4.2 this used to work great, but since upgrading to 1.10.2 it still works, but only ONCE. Meaning, if you click on 'Parent 1', it works. Then you deselect 'Parent 1' and it also works, but if you then click 'Parent 1' to select it again, it doesn't work anymore.

What is wrong here?

Just in case, here is the HTML:

<form>
<fieldset>
<input type="checkbox" class="parentCheckBox" /> Parent 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 1-1<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 1-2<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 1-3<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 1-4<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 1-5<br />
</fieldset>
<fieldset>
<input type="checkbox" class="parentCheckBox" /> Parent 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 2-1<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 2-2<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 2-3<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 2-4<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 2-5<br />
</fieldset>
<fieldset>
<input type="checkbox" class="parentCheckBox" /> Parent 3<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 3-1<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 3-2<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 3-3<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 3-4<br />
&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" class="childCheckBox" /> Child 3-5<br />
</fieldset>
</form>

And the jQuery:

$(document).ready(
    function() {
        //clicking the parent checkbox should check or uncheck all child checkboxes
        $(".parentCheckBox").click(
            function() {
                $(this).parents('fieldset:eq(0)').find('.childCheckBox').attr('checked', this.checked);
            }
        );
        //clicking the last unchecked or checked checkbox should check or uncheck the parent checkbox
        $('.childCheckBox').click(
            function() {
                if ($(this).parents('fieldset:eq(0)').find('.parentCheckBox').attr('checked') == true && this.checked == false)
                    $(this).parents('fieldset:eq(0)').find('.parentCheckBox').attr('checked', false);
                if (this.checked == true) {
                    var flag = true;
                    $(this).parents('fieldset:eq(0)').find('.childCheckBox').each(
                        function() {
                            if (this.checked == false)
                                flag = false;
                        }
                    );
                    $(this).parents('fieldset:eq(0)').find('.parentCheckBox').attr('checked', flag);
                }
            }
        );
    }
);
ekad
  • 14,436
  • 26
  • 44
  • 46
user2643870
  • 965
  • 1
  • 10
  • 19

3 Answers3

4

just change the following line in your code

$(this).parents('fieldset:eq(0)').find('.childCheckBox').attr('checked', this.checked);

with :

$(this).parents('fieldset:eq(0)').find('.childCheckBox').prop('checked', this.checked);
Ankit Tyagi
  • 2,381
  • 10
  • 19
1

Use .prop() instead of .attr()

Working fiddle

.prop('checked', this.checked);

There is a difference between an attribute and a property of an element. The attribute is the initial state, and the property is the current state.

You are setting the attribute of the options, which only works when the element doesn't have the attribute to begin with. After that the property takes over and setting the attribute has no effect on the current state any more.

When you want to change the selection state, you want to set the property instead of the attribute:

Read .prop() vs .attr()

Community
  • 1
  • 1
Tushar Gupta - curioustushar
  • 58,085
  • 24
  • 103
  • 107
0

I was having a hard time following your code but I came up with this which may be easier to read. What everyone else said about .prop() and .attr() is true.

I think this will work the way you'd like.

$('fieldset')
  .on('change', '.parentCheckBox', function(){

    var $parentCheckBox = $(this),
        $childCheckBoxes = $parentCheckBox.closest('fieldset').find('.childCheckBox');

    if( $childCheckBoxes.filter(':checked').length > 0 ){
      $childCheckBoxes.prop('checked', false);
      $parentCheckBox.prop('checked', false);
    } else {
      $childCheckBoxes.prop('checked', true);
    }

  })
  .on('change', '.childCheckBox', function(){

    var $this = $(this)
        $childCheckBoxes = $this.closest('fieldset').find('.childCheckBox'),
        $parentCheckBox = $this.closest('fieldset').find('.parentCheckBox'),
        allSelected = $childCheckBoxes.filter(':checked').length === $childCheckBoxes.length;

    $parentCheckBox.prop('checked', allSelected);

  });

Here's quick demo: http://jsbin.com/eriSaha/4/edit?js,output

Bill Criswell
  • 32,161
  • 7
  • 75
  • 66