...

View Full Version : Add Class to Parent of Nested Lists



kavaXtreme
08-31-2007, 09:33 PM
I'm trying to add a class name to list items that contain lists, excluding the root list. I don't think it's that hard to do, but I can't for the life of me figure out how to do it. Here's the concept:


<ul> << should not get class
<li>
<ul>
<li> << this and any li below it that contain lists need a class indicating they contain children
<ul>
<li></li>
<li></li>
</ul>
</li>
</ul>
</li>
</ul>


Not knowing any better, my preference is for an approach that uses getElementsByTagName. I just don't know how to select the right elements. Is there a "best practice" method for doing this?

Any help would be MUCH appreciated.

GJay
08-31-2007, 09:41 PM
this is an ideal case for one of the many js libraries that give you css selector support, using prototype.js (http://prototypejs.org) you would do:


$$('ul li ul').each(function(list) {
list.up('li').addClassName('has_children');
});


jQuery, yui, dojo and mootools all (I think) have similar functionality

[edit] misread, minor correction

[edit]some explanation:
the $$() function takes a 'css selector' and returns an array of matching elements- in this case we use 'ul li ul' which (starting from the right) means 'all ul-elements that are inside an li-element which in turn are inside a ul-element'.

The each() method on arrays takes a function as its argument, and applies it to 'each' element of the array. The function receives as an argument each item from the array, in turn.

prototype.js gives us the 'up()' method on elements, which (in this case) returns the first 'ancestor' (parent, or parent's parent and so on) that matches the given tag (it's a little less brittle than 'parentNode', and is automagically extended by prototype- using parentNode directly in IE won't work).

We then call the addClassName() method (again, a prototype.js thing) that should be fairly self explanatory.

kavaXtreme
08-31-2007, 10:10 PM
I had thought about looking into a Mootools or JQuery solution, but it's just for a simple menu, so those seem like overkill and I'd like to avoid the extra load time/bandwidth.

Is there a simple way to do this using regular JS?

rwedge
08-31-2007, 11:03 PM
For your example:
<ul> << should not get class
<li>
<ul>
<li> << this and any li below it that contain lists need a class indicating they contain children
<ul>
<li></li>
<li></li>
</ul>
</li>
</ul>
</li>
</ul>

A loop would do
<script type="text/javascript">
mylist = document.getElementsByTagName('li');
for (var i = 1;i < mylist.length; i++) {
mylist[i].className = 'myclass';
}
</script>

kavaXtreme
08-31-2007, 11:17 PM
Wouldn't that just add a class to all li tags? I'm looking for a solution that would only add a class to list elements that contain lists, excluding the parent/root list.

Basscyst
08-31-2007, 11:35 PM
<script type="text/javascript">
mylist = document.getElementsByTagName('li');
for (var i = 0;i < mylist.length; i++) {
kidLists=mylist[i].getElementsByTagName('li');
for(var j=0;j<kidLists.length;j++){
kidLists[j].className="myclass";
}
}
</script>


I think that'll work, didn't test.

rwedge
08-31-2007, 11:57 PM
Wouldn't that just add a class to all li tags? I'm looking for a solution that would only add a class to list elements that contain lists, excluding the parent/root list.
For your posted example, since the loop starts on the second li element, the output of the loop would be
<ul> << should not get class
<li>
<ul>
<li class="myclass"> << this and any li below it that contain lists need a class indicating they contain children
<ul>
<li class="myclass"></li>
<li class="myclass"></li>
</ul>
</li>
</ul>
</li>
</ul>

Basscyst
09-01-2007, 12:18 AM
I'm sure he has more than just that list on his page. What if there are other li elements on the page. All that does is skip the first li, which could cause undesired results.

kavaXtreme
09-01-2007, 02:57 AM
Hmm. Still can't get it to work. (Sorry, I don't have a public link.)

@Basscyst
I gave that code a shot, but it just seems to add the class to all LI elements except the root's.

To explain the reason I need this class: I want to put a little arrow in the menu to indicate which menu items contain sub-items. Make sense?

rwedge
09-01-2007, 03:26 AM
Set a class for each ul group you wish to add the li class to:
<ul class="menu"> << should not get class
<li>
<ul>
<li> << this and any li below it that contain lists need a class indicating they contain children
<ul>
<li></li>
<li></li>
</ul>
</li>
</ul>
</li>
</ul>


<script type="text/javascript">
var myULs = document.getElementsByTagName('ul');
for (var i = 0;i < myULs.length; i++) {
if (myULs[i].className === 'menu') {
var subULs = myULs[i].getElementsByTagName('ul');
for (j = 0;j < subULs.length-1;j++) {
subULs[j].getElementsByTagName('li')[0].className = 'myclass';
}
}
}
</script>



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum