jquery subgrouped checkboxes
I have a country list. It's splitted up 3 times.
[ ] World
[ ] Africa
[ ] Congo
[ ] Europe
[ ] Netherlands, the
[ ] Italy
now if I click world, I want all of them to be checked. If I click Africa, I only want Congo to be checked. If I click Europe, Both Italy and Netherlands, the should be checked. If I click Netherlands, the, and Italy, Europe should be checked, and the same should happen with World when clicking Europe and Africa. I came up with the following jquery script for it:
$(function() {
$(":checkbox").click(function() {
var maxlevel = 3;
var leve开发者_运维技巧l = $(this).attr("class").substring(5, 6);
var level_checked = $(this).attr("checked");
//update children
$('input', $(this).parent('div')).each(function() {
var curlevel = $(this).attr("class").substring(5, 6);
if (curlevel > level) {
$(this).attr("checked", level_checked);
}
});
//update parents?
});
});
I am using the following html code:
<div>
<input class="layer1" type="checkbox" />Layer1 <br />
<div>
<input class="layer2" type="checkbox" />Layer2 <br />
<div>
<input class="layer3" type="checkbox" />Layer3 <br />
<input class="layer3" type="checkbox" />Layer3 <br />
</div>
</div>
<div>
<input class="layer2" type="checkbox" />Layer2 <br />
<div>
<input class="layer3" type="checkbox" />Layer3 <br />
<input class="layer3" type="checkbox" />Layer3 <br />
</div>
</div>
</div>
Updating the children when clicking something works, but updating the parents when clicking a box.. I have no idea how to get that done. I found 2 pieces of code that did this, but they only worked for 1 'subgroup' of checkboxes, and not for 2 like in my case.
Can anyone help me out here?
Welcome to algorithms class. Here's the basic format:
Write the question down, as something which can be answered. This is step 1.
Step 2, write the answer down as a series of steps, and make each step as detailed as reasonable.
Step 3, convert each specific step into either code or pseudocode (repeating step 3 to convert pseudocode to code).
Congratulations, you've now implemented an algorithm in code. So for your specific question, I'll do the first two steps, and let you do the third:
How do I check all of the parent checkboxes of a given checkbox when it gets clicked?
sidenote: this is a recursive function. Any checkbox which gets called may need this called on it, but only for non-sibling checks. So you have two routes to consider. I'll consider the sibling route.
consider also that the parent of a child element may be semi-checkable or only support on/off states. I'll call that SEMI in my notes. You will choose one path based on if SEMI is in effect.
- A checkbox is activated.
- There are two states: The checkbox could now be unchecked, or it could now be checked.
- If the checkbox is now unchecked
- (SEMI) check to see if any sibling elements are checked, and if so, mark the parent as semi-checked OR
- uncheck the parent if that semi-check state is not supported.
- If the checkbox is now checked
- (SEMI) check to see if any sibling elements are unchecked, and if so, mark the parent as semi-checked OR
- check to see if all sibling elements are checked
- if all siblings are checked, mark parent as checked
- else mark parent as unchecked
- call this operation on the element's parent element, if the element is not the root element
How do I check all of the sibling checkboxes to determine their state?
- obtain a list of all the sibling elements for a given element
- define a variable for checked, and a variable for unchecked, and a variable for the total number of elements (counter)
- visit each checkbox in the sibling group and increment the appropriate counter for checked or unchecked, and increment the counter variable regardless of which other one you increment.
- If determining if all the siblings are unchecked, compare the counter to the unchecked
- If determining if any siblings are unchecked, compare the unchecked value to 0 (greater than zero means at least one is unchecked)
- If determining if all the siblings are checked, compare the counter to the checked
- If determining if any siblings are checked, compare the checked value to 0 (greater than zero means at least one is checked)
Note that there are faster/easier inline methods for determining the answer to #2, but depending on how you abstract it, that is an easy method to implement and only requires upkeep in one place.
I don't doubt that when you posted this question you were hoping for an easy answer, and while there are some shortcuts, this is the simplest way (and simplest is always most maintainable) so do it the simplest way for now. When you have specific code that you want to optimize that can be done later.
If you do as I helped you here, and write the long code, you'll be able to accomplish what you want.
$(function() {
var uncheck_parent = function(elt) {
var parent_div = elt.parent("div"),
parent_cb = parent_div.parent("div").children(":checkbox").first();
if (parent_cb.length == 0) return;
parent_cb.attr("checked", false);
uncheck_parent(parent_cb);
}
$(":checkbox").click(function() {
var maxlevel = 3;
var level = $(this).attr("class").substring(5, 6);
var level_checked = $(this).attr("checked");
//update children
$('input', $(this).parent('div')).each(function() {
var curlevel = $(this).attr("class").substring(5, 6);
if (curlevel > level) {
$(this).attr("checked", level_checked);
}
});
//update parents?
if (!$(this).is(":checked")) {
uncheck_parent($(this))
}
});
});
I think this will do what you want. I haven't been able to test it yet though. Basically it triggers a checkbox click on the elements that need checking when it decides this is necessary. It isn't too efficient, but the code is fairly simple.
$(function() {
$(":checkbox").click(function() {
$this = $(this);
if $this.is(':checked').length != 0) {
// We are UNCHECKING
//update children
$this.siblings('div').children('input').is(':checked').trigger('click');
//update parents if necessary
var all_unchecked = true;
$this.siblings('input').each(function(){
if($(this).is(':not(:checked')).length == 0) {all_unchecked = false}
}
if (all_unchecked) {
$this.parent().siblings('input').is(':checked').trigger('click');
});
} else {
// We are CHECKING
//update children
$this.siblings('div').children('input').is(':not(:checked)').trigger('click');
//update parents if necessary
var all_checked = true;
$this.siblings('input').each(function(){
if($(this).is(':checked').length == 0) {all_checked = false}
}
if (all_checked) {
$this.parent().siblings('input').is(':not(:checked)').trigger('click');
});
}
});
});
精彩评论