...

View Full Version : hierarchical selection



azazel
01-05-2004, 12:26 AM
hi!

here's the situation:

an outline format list of files that the user can pick to download. each file has a checkbox. i want the user to be able to select all the files in a sublevel by clicking the checkbox for that level.

visualize:
(x shall be checkbox)


x top level
x sub level
x bottom level
x bottom level
x sub level
x bottom level
x bottom level


clicking the top level would select everything. clicking a sub level would select the files underneath that level. clicking a bottom level would only select that file.

also, i'd like it to work backwards too. if a user deselects a file on the bottom level, the sublevel directly above that should uncheck.

is this even possible with javascript? have i bitten off more than i can chew? if so, suggestions for a more elegant way to approach this would be appreciated.

thanks in advance!

attached is a bare beginning...

Danne
01-05-2004, 09:51 PM
A recursive function should solve it:



<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
<script>
function check(f,isChild) {

/* Returns an array with children inputs */
function getChildren(f) {
var childContainer=f.nextSibling;
while (childContainer && childContainer.tagName!="BLOCKQUOTE") {
childContainer=childContainer.nextSibling;
}
if (childContainer) {
return childContainer.getElementsByTagName("INPUT");
} else {
return [];
}
}

/* Checks / unchecks all parents */
function checkParent(f,checked) {
var p=f.parentNode.previousSibling;
while (p && p.tagName!="INPUT") {
p=p.previousSibling;
}
if (p) {
var fields=getChildren(p);
for (var i = 0; i < fields.length; i++) {
if (!fields[ i ].checked) {
checked=false;
}
}
p.checked=checked;
checkParent(p,checked);
}
}

var checked=f.checked;

/* Check / uncheck all children */
var fields=getChildren(f);
for (var i = 0; i < fields.length; i++) {
fields[ i ].checked = checked;
check(fields[ i ],true);
}

/* Verify the state of the parents to calling node */
if (typeof isChild=="undefined") {
checkParent(f,checked);
}
}
</script>
<title>Test JS</title>

</head>
<body>

<form name="form">
<input type="checkbox" onclick="check(this);" />top level<br />
<blockquote>
<input type="checkbox" onclick="check(this);" />sublevel<br />
<blockquote>
<input type="checkbox" onclick="check(this);" />bottom level<br />
<input type="checkbox" onclick="check(this);" />bottom level
</blockquote>
<input type="checkbox" onclick="check(this);" />sublevel<br />
<blockquote>
<input type="checkbox" onclick="check(this);" />bottom level<br />
<input type="checkbox" onclick="check(this);" />bottom level
</blockquote>
</blockquote>
</form>
</body>
</html>

The first step is to loop down through the hierarchy and check/uncheck the children. This is done by identifying the the container, which is a sibling to the <input> (in this case <blockquote>), and getting all inputs from this container, using the getChildren() function.

The second step is to check whether the parent(s) should be checked. This is done by calling another recursive function - checkParent() - to loop up through the hierarchy.

azazel
01-05-2004, 10:34 PM
ah! that's beautiful! that's the first javascript i've seen that actually uses the strengths of the language. (i say that like i know what i'm talking about. in reality, that's first thing i'd ever seen about "children" and so on... :) )

anyway, i have one question: what if i don't use blockquotes? in my actual application, i'm using <div> tags to format my list. each div has a unique name. like this:



<div class="section">
<input type="checkbox" id="firstsection"> Section One</input>
</div>
<div class="subsection">
<input type="checkbox" id="firstsubsection"> Subsection One</input>
</div>
<div class="file">
<input type="checkbox"> File One</input>
</div>
<div class="file">
<input type="checkbox"> File Two</input>
</div>
<div class="subsection">
<input type="checkbox" id="secondsubsection"> Subsection Two</input>
</div>
<div class="file">
<input type="checkbox"> File One</input>
</div>
<div class="file">
<input type="checkbox"> File Two</input>
</div>
<div class="section">
<input type="checkbox" id="secondsection"> Section Two</input>
</div>


would that even be possible with the code you've provided? if not, i may have to rethink my formatting... keep in mind, this is dynamically generated, however.

thanks again!

Danne
01-05-2004, 11:11 PM
If you rearrange your HTML a little, to better describe the parent-child relation, it should work:



<div class="section">
<input type="checkbox" id="firstsection" onclick="check(this);"> Section One
<div class="subsection">
<input type="checkbox" id="firstsubsection" onclick="check(this);"> Subsection One
<div class="file">
<input type="checkbox" onclick="check(this);"> File One
<input type="checkbox" onclick="check(this);"> File Two
</div>
<input type="checkbox" id="secondsubsection" onclick="check(this);"> Subsection Two
<div class="file">
<input type="checkbox" onclick="check(this);"> File One
<input type="checkbox" onclick="check(this);"> File Two
</div>
</div>
</div>
<div class="section">
<input type="checkbox" id="secondsection" onclick="check(this);"> Section Two
</div>



You also need to change this line


while (childContainer && childContainer.tagName!="BLOCKQUOTE") {

to this:


while (childContainer && childContainer.tagName!="DIV") {


If you don't want to change the HTML, you need to modify the getChildren-function to return the children in a different way. A good DOM reference (http://www.mozilla.org/docs/dom/domref/) can help you to do that.

azazel
01-05-2004, 11:52 PM
thanks! that's actually exactly what i ended up doing. the added bonus is that my html is a lot cleaner now. :)

thanks for your time and effort!

Danne
01-06-2004, 01:29 PM
You're welcome...:thumbsup:



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum