Paul
Paul

Reputation: 1545

select parent node if all children have assigned class

I am looking for an efficient way to traverse a unordered list which contains multiple levels which contain the class .selected. If all the UL LI in a group have the class .selected, I need to add the class .selected the parent LI of the child UL.

<ul>
    <li>one <-- this li adds class .selected if ALL its children have .selected
        <ul>
            <li class="selected">red</li>
            <li class="selected">green</li>
            <li class="selected">blue</li>
        </ul>
    </li>
    <li>two
        <ul>
            <li class="selected">red</li>
            <li>green</li>
            <li class="selected">blue</li>
        </ul>
    </li>
    <li>three</li>
</ul>

if ALL the children in any given UL have the class .selected add the class .selected to the parent LI, so in this case the LI containing the text "one" would be the only parent LI to have the class .selected added.

I need this to happen when the page loads. and I have tried a bunch of methods but this one came closest but I am not too sure if its the most efficient:

$("ul li").filter(function () {
    var lis_total = $(this).siblings().length + 1;
    var lis_selected = $(".selected", this).siblings().length + 1;
    if(lis_total == lis_selected)
        return $(this).parent("li").addClass("selected");
});

I am not too sure if I am doing it correctly. Its not working.

Upvotes: 3

Views: 745

Answers (4)

Dom Day
Dom Day

Reputation: 2562

if you want a one-liner, try http://jsfiddle.net/4JNaL/

$('li ul:not(:has(li:not(.selected)))').parent().addClass('selected');

or

var theParent = $('li ul:not(:has(li:not(.selected)))').parent();

to return the element for manipulation

for trees of arbitrary depth: http://jsfiddle.net/GQbmU/4/

do {
    $results = $('li:not(.selected) > ul:not(:has(li:not(.selected)))');
    $results.parent().addClass('selected');
} while ( $results.length > 0);

or, since the theme of this answer is one-liners: http://jsfiddle.net/GQbmU/6/

while ( $('li:not(.selected) > ul:not(:has(li:not(.selected)))').parent().addClass('selected').length > 0) {} ;

Upvotes: 3

Roko C. Buljan
Roko C. Buljan

Reputation: 206121

http://jsbin.com/ecixez/2/edit

$('li>ul:has(.selected)').each(function(){
  if($('.selected', this).length === $('li',this).length) // if 3 == 3 :)
    $(this).parent().addClass('selected');
});

Upvotes: 1

DevlshOne
DevlshOne

Reputation: 8457

$(function () {
    $("ul").filter(function () {
        var lis_total = $(this).children("li").length + 1;
        var lis_selected = $(this).children("li.selected").length + 1;
        if (lis_total == lis_selected) {
            $(this).parent("li").addClass("selected");
        }
    });
});

Upvotes: 1

PSL
PSL

Reputation: 123739

Something like this?

$("ul li").filter(function () {
    var all = $(this).find('> ul > li'); //get all immediate ul and its immediate li's
    var selected = $(this).find('> ul > li.selected'); //get all immediate ul and its immediate li's with class selected

   return all.length && all.length == selected.length; //return if there are li's and all are selected
}).addClass('selected'); //add class

Demo

Upvotes: 3

Related Questions