Mr_Thomas
Mr_Thomas

Reputation: 869

Javascript - Expand/Collapse table rows

Given the following table/code, I'd like to add two items. I don't know JavaScript well enough and this code was left by another programmer. The code works as expected in every other way.

Here are the two items:

  1. The table should start in a collapsed state. All nodes should be collapsed to the 'Grandparent' level.
  2. There should be a link for 'expand all' and a separate 'collapse all' link.

Here is the table I'm using:

$(function() {
        $('#mytable').on('click', '.toggle', function () {
            var findChildren = function (tr) {
                var depth = tr.data('depth');
                return tr.nextUntil($('tr').filter(function () {
                    return $(this).data('depth') <= depth;
                }));
            };
    
            var el = $(this);
            var tr = el.closest('tr');
            var children = findChildren(tr);
    
            var subnodes = children.filter('.expand');
            subnodes.each(function () {
                var subnode = $(this);
                var subnodeChildren = findChildren(subnode);
                children = children.not(subnodeChildren);
            });
    
            if (tr.hasClass('collapse')) {
                tr.removeClass('collapse').addClass('expand');
                children.hide();
            } else {
                tr.removeClass('expand').addClass('collapse');
                children.show();
            }
            return children;
        });
    });
table td, th {
        border: 1px solid #eee;
        font-family: Arial;
        font-size: 16px;
    }
    .level0 td:first-child {
        padding-left: 5px;
    }
    .level1 td:first-child {
        padding-left: 25px;
    }
    .level2 td:first-child {
        padding-left: 50px;
    }
    .level3 td:first-child {
        padding-left: 75px;
    }
    
    .collapse .toggle {
        background: url("open.gif");
        background-repeat: no-repeat;
    }
    .expand .toggle {
        background: url("closed.gif");
        background-repeat: no-repeat;
    }
    .toggle {
        height: 20px;
        width: 20px;
        display: inline-block;
    }
    .age {
            text-align: center;
    }
    .nam {
            text-align: left;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<table id="mytable" style="border-collapse: collapse" cellpadding="6">
        <thead>
        <tr>
            <th width="250px">Type</th>
            <th width="50px">Age</th>
            <th width="50px">Name</th>
        </tr>
        </thead>
    
        <tr data-depth="0" class="collapse level0">
            <td><span class="toggle collapse"></span>GRANDPARENT</td>
            <td class="age">80</td>
            <td class="nam">Ethel</td>
        </tr>
    
        <tr data-depth="1" class="collapse level1">
            <td><span class="toggle"></span>CHILD 1</td>
            <td class="age">55</td>
            <td class="nam">Susan</td>
        </tr>
    
        <tr data-depth="2" class="collapse level2">
            <td><span class="toggle collapse"></span>GRANDCHILD 1</td>
            <td class="age">32</td>
            <td class="nam">Kristen</td>
        </tr>
    
        <tr data-depth="3" class="collapse collapsable level3">
            <td>GREAT GRANCHILD 1</td>
            <td class="age">12</td>
            <td class="nam">Layla</td>
        </tr>
    
        <tr data-depth="1" class="collapse collapsable level1">
            <td><span class="toggle collapse"></span>CHILD 2</td>
            <td class="age">52</td>
            <td class="nam">Joanne</td>
        </tr>
    
        <tr data-depth="2" class="collapse collapsable level2">
            <td><img src="list.gif"/>GRANDCHILD 2</td>
            <td class="age">28</td>
            <td class="nam">Marie</td>
        </tr>
    
    </table>

What do I need to add to the JavaScript to accomplish this?

Upvotes: 3

Views: 9151

Answers (1)

Takit Isy
Takit Isy

Reputation: 10081

Is this the kind of result you want ?
(I played a little with your code to make it work more or less like I think it should.)

Anyway, I don't understand all about what has been done, and I propose you only a JS solution.
But… I think the classes in your trs could be modified to get your “all hidden” result at the loading of the page without using any JS.
I commented where I added the new things:
EDIT: And I cleaned a little the code, too.

$('.collapse').on('click', function() {
  //console.log($(this).attr('data-depth'));
  var findChildren = function(tr) {
    var depth = tr.data('depth');
    return tr.nextUntil($('tr').filter(function() {
      return $(this).data('depth') <= depth;
    }));
  };

  var children = findChildren($(this));
  if ($(children).is(':visible')) {
    $(this).addClass("closed");
    $(children).hide();
  } else {
    $(this).removeClass("closed");
    $(children).show();
    var children = findChildren($(".closed"));
    $(children).hide();
  }

});


// HERE IS THE CODE I ADDED
$('#show_all').on('click', function() {
  $("#mytable tr.collapse").removeClass("closed").show();
});
$('#hide_all').on('click', function() {
  $("#mytable tr.collapse:not([data-depth='0'])").hide();
  $("#mytable tr.collapse.level0").addClass("closed");
});
$(document).ready(function() {
  $('#hide_all').trigger('click');
});
table td,
th {
  border: 1px solid #eee;
  font-family: Arial;
  font-size: 16px;
}

.level0 td:first-child {
  padding-left: 10px;
}

.level1 td:first-child {
  padding-left: 30px;
}

.level2 td:first-child {
  padding-left: 50px;
}

.level3 td:first-child {
  padding-left: 70px;
}

.age {
  text-align: center;
}

.nam {
  text-align: left;
}

.closed td:first-child::before {
  content: "• ";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- HERE IS THE HTML I ADDED FOR THE BUTTONS -->
<button id="show_all"><p>Show all</p></button>
<button id="hide_all"><p>Hide all</p></button>
<!-- END -->

<table id="mytable" style="border-collapse: collapse" cellpadding="6">
  <thead>
    <tr>
      <th width="250px">Type</th>
      <th width="50px">Age</th>
      <th width="50px">Name</th>
    </tr>
  </thead>

  <tr data-depth="0" class="collapse level0">
    <td>GRANDPARENT</td>
    <td class="age">80</td>
    <td class="nam">Ethel</td>
  </tr>

  <tr data-depth="1" class="collapse level1">
    <td>CHILD 1</td>
    <td class="age">55</td>
    <td class="nam">Susan</td>
  </tr>

  <tr data-depth="2" class="collapse level2">
    <td>GRANDCHILD 1</td>
    <td class="age">32</td>
    <td class="nam">Kristen</td>
  </tr>

  <tr data-depth="3" class="collapse level3">
    <td>GREAT GRANCHILD 1</td>
    <td class="age">12</td>
    <td class="nam">Layla</td>
  </tr>

  <tr data-depth="1" class="collapse level1">
    <td>CHILD 2</td>
    <td class="age">52</td>
    <td class="nam">Joanne</td>
  </tr>

  <tr data-depth="2" class="collapse level2">
    <td>GRANDCHILD 2</td>
    <td class="age">28</td>
    <td class="nam">Marie</td>
  </tr>

</table>

And here is the snippet before my last edition, in case the “cleaned” one doesn't fit your needs:

$('.collapse').on('click', function() {
  //console.log($(this).attr('data-depth'));
  var findChildren = function(tr) {
    var depth = tr.data('depth');
    return tr.nextUntil($('tr').filter(function() {
      return $(this).data('depth') <= depth;
    }));
  };

  var children = findChildren($(this));
  if ($(children).is(':visible')) {
    $(children).hide();
  } else {
    $(children).show();
  }

});


// HERE IS THE CODE I ADDED
$('#show_all').on('click', function() {
  $("#mytable tr.collapse:not([data-depth='0'])").show();
});
$('#hide_all').on('click', function() {
  $("#mytable tr.collapse:not([data-depth='0'])").hide();
});
$(document).ready(function() {
  $('#hide_all').trigger('click');
});
table td,
th {
  border: 1px solid #eee;
  font-family: Arial;
  font-size: 16px;
}

.level0 td:first-child {
  padding-left: 5px;
}

.level1 td:first-child {
  padding-left: 25px;
}

.level2 td:first-child {
  padding-left: 50px;
}

.level3 td:first-child {
  padding-left: 75px;
}

.collapse .toggle {
  background: url("open.gif");
  background-repeat: no-repeat;
}

.expand .toggle {
  background: url("closed.gif");
  background-repeat: no-repeat;
}

.toggle {
  height: 20px;
  width: 20px;
  display: inline-block;
}

.age {
  text-align: center;
}

.nam {
  text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- HERE IS THE HTML I ADDED -->
<button id="show_all"><p>Show all</p></button>
<button id="hide_all"><p>Hide all</p></button>
<!-- END -->

<table id="mytable" style="border-collapse: collapse" cellpadding="6">
  <thead>
    <tr>
      <th width="250px">Type</th>
      <th width="50px">Age</th>
      <th width="50px">Name</th>
    </tr>
  </thead>

  <tr data-depth="0" class="collapse level0">
    <td><span class="toggle collapse"></span>GRANDPARENT</td>
    <td class="age">80</td>
    <td class="nam">Ethel</td>
  </tr>

  <tr data-depth="1" class="collapse level1">
    <td><span class="toggle"></span>CHILD 1</td>
    <td class="age">55</td>
    <td class="nam">Susan</td>
  </tr>

  <tr data-depth="2" class="collapse level2">
    <td><span class="toggle collapse"></span>GRANDCHILD 1</td>
    <td class="age">32</td>
    <td class="nam">Kristen</td>
  </tr>

  <tr data-depth="3" class="collapse collapsable level3">
    <td>GREAT GRANCHILD 1</td>
    <td class="age">12</td>
    <td class="nam">Layla</td>
  </tr>

  <tr data-depth="1" class="collapse collapsable level1">
    <td><span class="toggle collapse"></span>CHILD 2</td>
    <td class="age">52</td>
    <td class="nam">Joanne</td>
  </tr>

  <tr data-depth="2" class="collapse collapsable level2">
    <td><img src="list.gif" />GRANDCHILD 2</td>
    <td class="age">28</td>
    <td class="nam">Marie</td>
  </tr>

</table>

Upvotes: 5

Related Questions