buck1112
buck1112

Reputation: 498

Hide All Descendent Table Rows

I am working with jQuery in trying to toggle the children tr's of a parent tr.
This is working for one tr level at a time; however, when an inner tr collapses its children and then the outer one does the same, the children of the inner tr remain visible.
I want all descendents (the Level 2 and Level 3 classes) to be hidden when the Level 1 class is clicked, and I want the Level 3 class to be hidden when the Level 2 class is clicked.

Here's the code I've been using.

$(".mainTable td[class^='Level1']").each(function() {
    //copy td class to tr
    $(this).parent().addClass($(this).attr('class'));
    //add function to tr
    $(this).parent().click(function() {
        //toggle all elements to next Level1 class
        $(this).nextUntil("[class^='Level1']").toggle();
    });
});


$(".mainTable td[class^='Level2']").each(function() {
    //copy td class to tr
    $(this).parent().addClass($(this).attr('class'));
    //add function to tr
    $(this).parent().click(function() {
        //toggle all elements to next Level1 class
        $(this).nextUntil("[class^='Level1']").toggle();
    });
});

Here is the HTML:

<table class="mainTable">
    <tbody>
        <tr><td class="Level1">Level 1</td></tr>
        <tr><td class="Level1">Level 1</td></tr>
        <tr><td class="Level2">Level 2</td></tr>
        <tr><td class="Level3">Level 3</td></tr>
        <tr><td class="Level1">Level 1</td></tr>
        <tr><td class="Level1">Level 1</td></tr>
        <tr><td class="Level2">Level 2</td></tr>
    </tbody>
</table>

Thanks for any help.

Upvotes: 0

Views: 104

Answers (2)

Olim Saidov
Olim Saidov

Reputation: 2844

This should do the job:

$(".mainTable td[class^=Level]").each(function() {
    $(this).parent().addClass($(this).attr('class'));
});

$(".mainTable tr[class^=Level1]").click(function() {
    var items = $(this).nextUntil("[class^=Level1]");

    if (items.filter(':hidden').length > 0) {
        items.show();
    }
    else {
        items.hide();
    }
});

$(".mainTable tr[class^=Level2]").click(function() {
    $(this).nextUntil("[class^=Level1], [class^=Level2]").toggle();
});

Demo here: jsFiddle

Upvotes: 0

Yury Tarabanko
Yury Tarabanko

Reputation: 45106

You can make this code more DRY. This should work for any levels depth. Demo.

function getLevel(el) { //extract level as integer from classname
    var level = /Level(\d+)/.exec(el.className)
    return level != null ? parseInt(level[1], 10) : NaN;    
}

$('.mainTable').on('click', 'td', function() { //use event delegation
    var level = getLevel(this), //get current level
        parent, state;
    if(level == level) { //checking for NaN              
        parent = $(this).parent('tr'); //get parent
        state = !!parent.data('state'); //get current state

        parent.nextUntil(function(_, item) { //filter lower levels
                    return getLevel(item.cells[0]) <= level;
               })
              .each(function(_, item) {
                    $(item).data('state', !state)
                           .toggle(state);
               }); //show|hide

        parent.data('state', !state); //save current state.
    }
});

If you can modify html you can greatly reduce code complexity by using data attributes.

<tr data-level="1">...</tr>
<tr data-level="3">...</tr>

Specifying levels like this you will eliminate all the string manipulations required to extract level in a form of number.

Upvotes: 1

Related Questions