JQuery expand / collapse hierarchical table row

I am looking for an efficient way to expand / collapse hierarchical rows of a table using jQuery. The problem is that the expand and collapse functionality is different.

  • At first, only rows with the class level_0 , all other rows are hidden.
  • expand should show only the next level, so clicking on the line id=10 should only do the lines with id=11 and id=14 .
  • a failure, on the other hand, should collapse all consecutive lines with a deeper level than the current one. For example, clicking collapse on line id=10 should hide lines with identifiers 11, 12, 13, 14 , if they are visible.

The table data is as follows:

 <table id="mytable"> <tr class="level_0" id="10">...</td> <tr class="level_1 parent_10" id="11">...</td> <tr class="level_2 parent_11" id="12">...</td> <tr class="level_2 parent_11" id="13">...</td> <tr class="level_1 parent_10" id="14">...</td> <tr class="level_0" id="15">...</td> </table> 

My inoperative solution:

 $('#mytable tr').live('click', function() { var toggleClass = 'parent_' + $(this).attr('id'); $(this).nextAll('tr').each(function() { if ($(this).is('.'+toggleClass)) { $(this).toggleClass("showme"); } }); }); 

The problem is that it only collapses the lines of the next level. Visible and deeper rows of levels below the clicked row are still displayed.


Can someone give me some tips on how I can do this in an efficient way? If necessary, the HTML code can be adjusted.

Thanks for any tips.

+6
javascript jquery expand
source share
3 answers

The html table in your message is invalid (tr is enclosed in td). On a properly structured table, this code works.

 $("tr.level_0").live("click", function () { $(this).nextUntil(".level_0").toggle(); }); 
+2
source share

I think you will need some more code so that you can handle clicks on all lines in a closed and open state.

I added a class switch to indicate when the line is open, and handle clicks differently based on state. Both collapse and expand have loops that go through the lines, starting with one immediately after the clicked line, and stop when they hit lines of the same level. This logic should work at any level, not just 0. In addition, the while would probably be cleaner using the nextUntil logic with a fancy selector - I was not familiar with this jQuery method until I saw Jules answer - very smooth!

In addition, to simplify this code example, I considered your level class name system as attributes of HTML data, so this line looks like this: <tr data-level="0" id="10"> . You could replace the calls to .data code to parse your class names.

 var $rows = $('#mytable tr'); $rows.live('click', function() { $(this).toggleClass('open'); if ($this.hasClass('open')){ collapse($(this)); } else { expand($this); } } function collapse ($row) { $row.removeClass('open'); var rowIndex = $rows.index($row); var siblingOrAncestorRowFound = false; while (!siblingOrAncestorRowFound){ var $nextRow = $rows.eq(rowIndex + 1); if ($nextRow.level > $row.level){ $nextRow.hide().removeClass('open'); rowIndex++; } else { siblingOrAncestorRowFound = true; } } } function expand ($row) { $row.addClass('open') var rowIndex = $rows.index($row); var siblingOrAncestorRowFound = false; while (!siblingOrAncestorRowFound){ var $nextRow = $rows.eq(rowIndex + 1); if ($nextRow.level > $row.level){ // only show rows exactly one level below if ($nextRow.level == $row.level + 1){ $nextRow.show(); } rowIndex++; } else { siblingOrAncestorRowFound = true; } } } 

(This is not verified - sorry, please remove the bag!)

0
source share

I created a version for several levels of the hierarchy as an answer to another question .

jQuery for your table will be:

 var treeTable = { parentClassPrefix : '', collapsedClass : 'collapsed', init : function(parentClassPrefix) { this.parentClassPrefix = parentClassPrefix; $('table').on('click', 'tr', function () { treeTable.toggleRowChildren($(this)); }); }, toggleRowChildren : function(parentRow) { var childClass = this.parentClassPrefix+parentRow.attr('id'); var childrenRows = $('tr', parentRow.parent()).filter('.'+childClass); childrenRows.toggle(); childrenRows.each(function(){ if (!$(this).hasClass(treeTable.collapsedClass)) { treeTable.toggleRowChildren($(this)); } }); parentRow.toggleClass(this.collapsedClass); } }; treeTable.init('parent_'); 

See JSFiddle for work.

Optimization

I have a slightly different table structure that includes an indication of the parents as well as the children so that the search can be more efficient.

Then I also made a hierarchical row of the jQuery table, switching the Gist , and converting it to objectified javascript with optimization. Optimizations come from http://24ways.org/2011/your-jquery-now-with-less-suck/ .

In particular:

Delegation of events in a table, not in rows.

 $('table').on('click', 'tr.'+treeTable.parentClass, function () { treeTable.toggleRowChildren($(this)); }); 

Cache for choosing children.

Use a faster element selector followed by a slower filter on .childClass

 var childrenRows = $('tr', parentRow.parent()).filter('.'+childClass); 
0
source share

All Articles