web-dev-qa-db-fra.com

développer / réduire les lignes d'un tableau avec JQuery

Je souhaite développer et réduire les lignes de la table lorsque l'utilisateur clique sur les colonnes d'en-tête. Je veux seulement développer/réduire les lignes qui sont sous l'en-tête spécifique (cliqué).

Voici la structure de ma table:

 <table border="0">
      <tr>
        <td colspan="2">Header</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td colspan="2">Header</td>
      </tr>
      <tr>
        <td>date</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
    </table>

Toute pensée sur comment puis-je accomplir cette tâche. L'utilisation de div cette tâche semble assez simple, mais j'ai des données tabulaires que je veux manipuler.

Une idée à laquelle je peux penser est d'utiliser la classe css dans chaque ligne qui distingue les lignes situées sous chaque en-tête et d'utiliser JQuery pour développer/réduire ces lignes uniquement lorsque vous cliquez sur l'en-tête. Mais si ma table a 10-15 en-têtes, il semble difficile de garder une trace des classes de CSS.

S'il vous plaît suggérer un moyen approprié pour y parvenir.

60
Saqib

Vous pouvez essayer de cette façon: -

Attribuez à la classe header les lignes d'en-tête, utilisez nextUntil pour obtenir toutes les lignes situées sous l'en-tête sur lequel vous avez cliqué jusqu'au prochain en-tête.

JS

$('.header').click(function(){
    $(this).nextUntil('tr.header').slideToggle(1000);
});

Html

<table border="0">
  <tr  class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>

démo

Un autre exemple:

$('.header').click(function(){
   $(this).find('span').text(function(_, value){return value=='-'?'+':'-'});
    $(this).nextUntil('tr.header').slideToggle(100); // or just use "toggle()"
});

démo

Vous pouvez également utiliser la promesse de basculer l'icône/le texte d'étendue une fois le basculement terminé en cas de basculement animé.

$('.header').click(function () {
    var $this = $(this);
    $(this).nextUntil('tr.header').slideToggle(100).promise().done(function () {
        $this.find('span').text(function (_, value) {
            return value == '-' ? '+' : '-'
        });
    });
});

. promise ()

. slideToggle ()

Ou simplement avec un pseudo élément css pour représenter le signe de l'expansion/réduction, et basculez simplement une classe sur l'en-tête.

CSS: -

.header .sign:after{
  content:"+";
  display:inline-block;      
}
.header.expand .sign:after{
  content:"-";
}

JS: -

$(this).toggleClass('expand').nextUntil('tr.header').slideToggle(100);

démo

126
PSL

Le moyen le plus simple d'y parvenir, sans changer la structure HTML table, consiste à utiliser un nom de classe sur les éléments tr contenant un en-tête, tel que .header, pour obtenir:

<table border="0">
  <tr class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>date</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
</table>

Et le jQuery:

// bind a click-handler to the 'tr' elements with the 'header' class-name:
$('tr.header').click(function(){
    /* get all the subsequent 'tr' elements until the next 'tr.header',
       set the 'display' property to 'none' (if they're visible), to 'table-row'
       if they're not: */
    $(this).nextUntil('tr.header').css('display', function(i,v){
        return this.style.display === 'table-row' ? 'none' : 'table-row';
    });
});

JS Fiddle démo .

Dans la démo liée, j'ai utilisé CSS pour masquer les éléments tr qui ne possèdent pas le nom de classe header ; dans la pratique cependant (malgré la rareté relative des utilisateurs avec JavaScript désactivé), je suggérerais d'utiliser JavaScript pour ajouter les noms de classe pertinents, en les masquant et en les affichant comme il convient:

// hide all 'tr' elements, then filter them to find...
$('tr').hide().filter(function () {
    // only those 'tr' elements that have 'td' elements with a 'colspan' attribute:
    return $(this).find('td[colspan]').length;
    // add the 'header' class to those found 'tr' elements
}).addClass('header')
    // set the display of those elements to 'table-row':
  .css('display', 'table-row')
    // bind the click-handler (as above)
  .click(function () {
    $(this).nextUntil('tr.header').css('display', function (i, v) {
        return this.style.display === 'table-row' ? 'none' : 'table-row';
    });
});

JS Fiddle démo .

Références:

12
David Thomas

J'ai développé l'une des réponses, mais ma fonctionnalité est un peu différente. Dans ma version, différentes lignes forment différents groupes. Et la ligne "en-tête" déclenche la réduction/expansion de ce groupe particulier. De plus, chaque sous-groupe mémorise son état. Cela peut paraître un peu déroutant, vous pouvez tester ma version avec jsfiddle. J'espère que ces extraits de code seront utiles à quelqu'un!

HTML

<table border="0">
  <tr>
      <th>Header 1</th>
      <th>Header 2</th>
  </tr>
  <tr>
    <td class='group1'>Group 1</td>
    <td>data 2</td>
  </tr>
  <tr class='group1'>
    <td>data 3</td>
    <td>data 4</td>
  </tr>
  <tr>
    <td class='group2'>Group 2</td>
    <td>data 2</td>
  </tr>
  <tr class='group2'>
    <td>data 3</td>
    <td>data 4</td>
  </tr>
  <tr class='group2'>
    <td class='sub_group1'>Sub Group 1</td>
    <td>data 6</td>
  </tr>
  <tr class='group2 sub_group1'>
    <td>data 7</td>
    <td>data 8</td>
  </tr>
  <tr class='group2 sub_group1'>
    <td>data 9</td>
    <td>data 10</td>
  </tr>
  <tr class='group2 sub_group1'>
    <td class='sub_sub_group1'>Sub Sub Group 1</td>
    <td>data 11</td>
  </tr>
  <tr class='group2 sub_group1 sub_sub_group1'>
    <td>data 12</td>
    <td>data 13</td>
  </tr>
  <tr class='group2 sub_group1 sub_sub_group1'>
    <td>data 14</td>
    <td>data 15</td>
  </tr>
  <tr class='group2'>
    <td class='sub_group2'>Sub Group 2</td>
    <td>data 11</td>
  </tr>
  <tr class='group2 sub_group2'>
    <td>data 12</td>
    <td>data 13</td>
  </tr>
  <tr class='group2 sub_group2'>
    <td>data 14</td>
    <td>data 15</td>
  </tr>
</table>

CSS

table, tr, td, th
{
    border: 1px solid black;
    border-collapse:collapse;
}

img.button_open{
  content:url('http://code.stephenmorley.org/javascript/collapsible-lists/button-open.png');
  cursor:pointer;
}

img.button_closed{
  content: url('http://code.stephenmorley.org/javascript/collapsible-lists/button-closed.png');
  cursor:pointer;
}

JS

function CreateGroup(group_name)
{
    // Create Button(Image)
    $('td.' + group_name).prepend("<img class='" + group_name + " button_closed'> ");
    // Add Padding to Data
    $('tr.' + group_name).each(function () {
        var first_td = $(this).children('td').first();
        var padding_left = parseInt($(first_td).css('padding-left'));
        $(first_td).css('padding-left', String(padding_left + 25) + 'px');
    });
    RestoreGroup(group_name);

    // Tie toggle function to the button
    $('img.' + group_name).click(function(){
        ToggleGroup(group_name);
    });
}

function ToggleGroup(group_name)
{
    ToggleButton($('img.' + group_name));
    RestoreGroup(group_name);
}

function RestoreGroup(group_name)
{
    if ($('img.' + group_name).hasClass('button_open'))
    {
        // Open everything
        $('tr.' + group_name).show();

        // Close subgroups that been closed
        $('tr.' + group_name).find('img.button_closed').each(function () {
            sub_group_name = $(this).attr('class').split(/\s+/)[0];
            //console.log(sub_group_name);
            RestoreGroup(sub_group_name);
        });
    }

    if ($('img.' + group_name).hasClass('button_closed'))
    {
        // Close everything
        $('tr.' + group_name).hide();
    }
}

function ToggleButton(button)
{
    $(button).toggleClass('button_open');
    $(button).toggleClass('button_closed');
}

CreateGroup('group1');
CreateGroup('group2');
CreateGroup('sub_group1');
CreateGroup('sub_group2');
CreateGroup('sub_sub_group1');

DÉMO

4
Barmaley

Je dirais qu'en utilisant l'attribut data- pour faire correspondre les en-têtes avec les éléments qu'il contient. Fiddle: http://jsfiddle.net/GbRAZ/1/

Un aperçu de l'altération HTML:

   <tr class="header" id="header1">
    <td colspan="2">Header</td>
   </tr>
   <tr data-for="header1" style="display:none">
     <td>data</td>
     <td>data</td>
   </tr>
   <tr data-for="header1" style="display:none">
     <td>data</td>
     <td>data</td>
   </tr>

Code JS:

$(".header").click(function () {
   $("[data-for="+this.id+"]").slideToggle("slow");
});

EDIT: Mais cela implique quelques modifications HTML. donc je ne sais pas si c'est ce que tu voulais. Une meilleure façon de structurer cela serait d'utiliser <th> ou de changer le code HTML entier pour utiliser ul, ol, etc ou même une configuration div > span.

4
krishgopinath

J'ai aimé la réponse la plus simple fournie. Cependant, je n'aimais pas le chahut de l'effondrement. J'ai donc combiné une solution de cette question: Comment utiliser la fonction slideDown (ou show) sur une ligne de tableau? pour en faire une animation plus fluide lorsque les lignes glissent vers le haut ou le bas. Cela implique de devoir envelopper le contenu de chaque td dans une div. Cela lui permet d'animer en douceur la réduction. Lorsque les lignes sont développées, cela remplacera la div, avec seulement le contenu.

Alors, voici le code HTML:

<table>
<tr class="header">
    <td>CARS</td>
</tr>
<tr class="thing">
    <td>car</td>
</tr>
<tr class="thing">
    <td>truck</td>
</tr>
<tr class="header">
    <td>HOUSES</td>
</tr>
<tr class="thing">
    <td>split level</td>
</tr>
<tr class="thing">
    <td>trailer</td>
</tr>

Et voici le js

$('.header').click(function(){
if($(this).hasClass("collapsed")){
    $(this).nextUntil('tr.header')
    .find('td')
    .parent()
    .find('td > div')
    .slideDown("fast", function(){
        var $set = $(this);
        $set.replaceWith($set.contents());
    });
    $(this).removeClass("collapsed");
} else {
    $(this).nextUntil('tr.header')
    .find('td')
    .wrapInner('<div style="display: block;" />')
    .parent()
    .find('td > div')
    .slideUp("fast");
    $(this).addClass("collapsed");
}
});

Commander ce violon pour un exemple https://jsfiddle.net/p9mtqhm7/52/

4