jQuery expand / collapse fila de la tabla jerárquica

Estoy buscando una manera eficiente de expandir / queuepsar filas de tablas jerárquicas usando jQuery. El problema es que la funcionalidad de expandir y queuepsar es diferente.

  • Inicialmente, solo se muestran las filas con el nivel de level_0 , todas las demás filas están ocultas.
  • expand debería mostrar únicamente el siguiente nivel, por lo que onclick en la fila id=10 solo se mostrarán las filas con id=11 e id=14 visibles.
  • queuepso por otro lado, debe queuepsar todas las filas consecutivas con un nivel más profundo que el actual. Por ejemplo, onclick en queuepsar en la fila id=10 deben ocultar las filas con los identificadores 11, 12, 13, 14 , si están visibles.

La tabla de datos se ve de la siguiente manera:

 <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> 

Mi solución no funcional:

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

El problema es que solo queuepsa las filas del siguiente nivel. Las filas de niveles visibles y más profundos debajo de la fila cliqueada todavía se muestran.


¿Alguien puede darme algunas pistas sobre cómo podría hacer esto de una manera eficiente? El código HTML se puede ajustar si es necesario.

Gracias por cualquier pista.

La tabla html en su publicación no es válida (tr incluida por td). En la tabla adecuadamente estructurada, este código funciona.

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

Creo que vas a necesitar un poco más de código para que puedas manejar los clics en todas las filas tanto en estados cerrados como abiertos .

Agregué un interruptor de class para indicar cuándo está abierta una fila y tratar los clics de manera diferente en function de su estado. Tanto el collapse como la expand tienen loops while que recorren filas, comenzando con el inmediatamente posterior a la fila cliqueada, y se detienen cuando llegan a filas del mismo nivel. Esta lógica debería funcionar para cualquier nivel, no solo 0. Además, el bucle while podría estar más limpio usando la lógica nextUntil con un selector elegante (no estaba familiarizado con el método jQuery hasta que no haya visto la respuesta de Jules) ¡muy astuto!

Además, para mantener este código de ejemplo más simple, traté su sistema de nombres de class de nivel como attributes de datos HTML, por lo que una fila determinada se ve así: <tr data-level="0" id="10"> . Podría replace las llamadas a .data con código para analizar los nombres de sus classs.

 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; } } } 

(Esto no se ha probado, ¡lamento golpear el saco!)

Creé una versión para múltiples niveles de jerarquía como respuesta a otra pregunta .

El jQuery para tu table sería:

 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_'); 

Vea este JSFiddle para que funcione.

Optimizaciones

Tengo una estructura de tabla ligeramente diferente, que implica especificar padres y niños para que la búsqueda sea más eficiente.

También hice una fila de la tabla jerárquica jQuery alternar Gist desde allí y la convertí en JavaScript objetivado con optimizaciones. Las optimizaciones provienen de http://24ways.org/2011/your-jquery-now-with-less-suck/ .

Específicamente:

Delegación de evento en la table en lugar de en las filas.

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

Guarde en caching la selección de niños.

Usa el selector de elementos más rápido seguido de un filter más lento en .childClass

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