使用 jquery/javascript 根据单元格值对表格行进行分组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31962725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 14:39:46  来源:igfitidea点击:

Grouping table rows based on cell value using jquery/javascript

javascriptjqueryhtmlcss

提问by user5215297

I have been trying to solve this for days.I would greatly appreciate any help you can give me in solving this problem. I have a table like the following:

几天来我一直在努力解决这个问题。我将不胜感激您在解决这个问题时能给我的任何帮助。我有一张如下表:

ID              Name            Study
1111            Angela          XRAY
2222            Bena            Ultrasound
3333            Luis            CT Scan
1111            Angela          Ultrasound
3333            Luis            XRAY
3333            Luis            LASER

and I want to group them like:

我想将它们分组如下:

ID              Name            Study
GROUP BY id(1111) 2 hits  "+"
2222            Bena            Ultrasound
GROUP BY id(3333) 3 hits "+"

AND if "+" is clicked then it will expand:

如果单击“+”,它将展开:

 ID              Name            Study
GROUP BY id(1111) 2 hits  "-"
1111            Angela          XRAY  
1111            Angela          Ultrasound
2222            Bena            Ultrasound
GROUP BY id(3333) 3 hits  "-"
3333            Luis            CT Scan
3333            Luis            Ultrasound
3333            Luis            LASER

There is a demo that I found on stackoverflow(http://jsfiddle.net/FNvsQ/1/) but the only problem I have is I want to include all rows having the same id under a dynamic header like

我在 stackoverflow( http://jsfiddle.net/FNvsQ/1/)上找到了一个演示,但我唯一的问题是我想在动态标题下包含所有具有相同 ID 的行,例如

grouped by id(1111) then the expand/collapse icon (+/-)

按 id(1111) 分组,然后是展开/折叠图标 (+/-)

var table = $('table')[0];
var rowGroups = {};
//loop through the rows excluding the first row (the header row)
while(table.rows.length > 0){
    var row = table.rows[0];
    var id = $(row.cells[0]).text();
    if(!rowGroups[id]) rowGroups[id] = [];
    if(rowGroups[id].length > 0){
        row.className = 'subrow';
        $(row).slideUp();
    }
    rowGroups[id].push(row);
    table.deleteRow(0);
}
//loop through the row groups to build the new table content
for(var id in rowGroups){
    var group = rowGroups[id];
    for(var j = 0; j < group.length; j++){
        var row = group[j];
        if(group.length > 1 && j == 0) {
            //add + button
            var lastCell = row.cells[row.cells.length - 1];           
            $("<span class='collapsed'>").appendTo(lastCell).click(plusClick);                                         
        }
        table.tBodies[0].appendChild(row);        
    }
}
//function handling button click
function plusClick(e){
    var collapsed = $(this).hasClass('collapsed');
    var fontSize = collapsed ? 14 : 0;
    $(this).closest('tr').nextUntil(':not(.subrow)').slideToggle(400)
           .css('font-size', fontSize);
    $(this).toggleClass('collapsed');        
}

回答by user5215297

Here is the answer to my own question.

这是我自己的问题的答案。

First id's are added to the table and the rows and there's a small change to the JS:

第一个 id 被添加到表和行中,对 JS 有一个小的变化:

var table = $('table')[0];
var rowGroups = {};

//loop through the rows excluding the first row (the header row)
while (table.rows.length > 1) {
  var row = table.rows[1];
  var id = $(row.cells[0]).text();

  if (!rowGroups[id]) rowGroups[id] = [];

  if (rowGroups[id].length > 0) {
    row.className = 'subrow';
    $(row).slideUp();
  }
  rowGroups[id].push(row);
  table.deleteRow(1);
}

//loop through the row groups to build the new table content
for (var id in rowGroups) {
  var group = rowGroups[id];

  for (var j = 0; j < group.length; j++) {
    var row = group[j];
    var notSubrow = false;

    if (group.length > 1 && j == 0) {
      //add + button
      var lastCell = row.cells[row.cells.length - 1];
      var rowId = row.id;
      var tableId = table.id;
      notSubrow = true;
      //$("<span class='collapsed'>").appendTo(lastCell).click(plusClick);                                         
    }
    table.tBodies[0].appendChild(row);

    if (notSubrow) {
      $('#' + tableId).find('#' + rowId).attr('class', 'subrow');
      $('#' + tableId).find('#' + rowId).before("<tr class='subrowHeader' style='background:#E6E6FA;border-bottom:1px solid #708AA0 !important'><td colspan='3'>&nbsp;group by&nbsp" + $(row.cells[0]).text() + "&nbsp;(" + group.length + ")" + "<span class='collapsed' onclick='plusClick(this)' style='float:left;display:inline'></td></tr>");
      $('#' + tableId).find('#' + rowId).hide();
    }
  }
}
//function handling button click
function plusClick(e) {
  var collapsed = $(e).hasClass('collapsed');
  var fontSize = collapsed ? 14 : 0;
  $(e).closest('tr').nextUntil(':not(.subrow)').slideToggle('fast').css('font-size', fontSize);
  $(e).toggleClass('collapsed');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table1">
  <tr id="tr1">
    <th>Parent ID</th>
    <th>Parent Name</th>
    <th>Study</th>
  </tr>
  <tr id="tr2">
    <td>1111</td>
    <td>Angela</td>
    <td>XRAY</td>
  </tr>
  <tr id="tr3">
    <td>2222</td>
    <td>Bena</td>
    <td>Untrasound</td>
  </tr>
  <tr id="tr4">
    <td>3333</td>
    <td>Luis</td>
    <td>CT Scan</td>
  </tr>
  <tr id="tr5">
    <td>1111</td>
    <td>Angela</td>
    <td>Untrasound</td>
  </tr>
  <tr id="tr6">
    <td>3333</td>
    <td>Luis</td>
    <td>LCD</td>
  </tr>
  <tr id="tr7">
    <td>3333</td>
    <td>Luis</td>
    <td>LASER</td>
  </tr>
</table>

*Inorder to test copy and paste the code into http://jsfiddle.net/FNvsQ/1/& In the Frameworks & Extensions panel, set onLoad to No wrap - in body.

*为了测试将代码复制并粘贴到http://jsfiddle.net/FNvsQ/1/& 在 Frameworks & Extensions 面板中,将 onLoad 设置为 No wrap - in body。

回答by RobG

As a comparison, here's a POJS function that is functionally equivalent in the same amount of code. Doesn't use a large external library though.

作为比较,这里有一个 POJS 函数,它在相同数量的代码中功能等效。虽然不使用大型外部库。

It uses the same algorithm of collecting all rows with the same value in the first cell, then modifies the table to insert header rows and group the data rows.

它使用相同的算法收集第一个单元格中具有相同值的所有行,然后修改表格以插入标题行并对数据行进行分组。

// Group table rows by first cell value. Assume first row is header row
function groupByFirst(table) {

  // Add expand/collapse button
  function addButton(cell) {
    var button = cell.appendChild(document.createElement('button'));
    button.className = 'toggleButton';
    button.textContent = '+';
    button.addEventListener('click', toggleHidden, false);
    return button;
  }

  // Expand/collapse all rows below this one until next header reached
  function toggleHidden(evt) {
    var row = this.parentNode.parentNode.nextSibling;
    
    while (row && !row.classList.contains('groupHeader')) {
      row.classList.toggle('hiddenRow');
      row = row.nextSibling;
    }
  }
  
  // Use tBody to avoid Safari bug (appends rows to table outside tbody)
  var tbody = table.tBodies[0];

  // Get rows as an array, exclude first row
  var rows = Array.from(tbody.rows).slice(1);
  
  // Group rows in object using first cell value
  var groups = rows.reduce(function(groups, row) {
    var val = row.cells[0].textContent;
    
    if (!groups[val]) groups[val] = [];
    
    groups[val].push(row);
    return groups;
  }, Object.create(null));
  
  // Put rows in table with extra header row for each group
  Object.keys(groups).forEach(function(value, i) {

    // Add header row
    var row = tbody.insertRow();
    row.className = 'groupHeader';
    var cell = row.appendChild(document.createElement('td'));
    cell.colSpan = groups[value][0].cells.length;
    cell.appendChild(
      document.createTextNode(
        'Grouped by ' + table.rows[0].cells[0].textContent +
        ' (' + value + ') ' + groups[value].length + ' hits'
      )
    );
    var button = addButton(cell);

    // Put the group's rows in tbody after header
    groups[value].forEach(function(row){tbody.appendChild(row)});
    
    // Call listener to collapse group
    button.click();
  });
}

window.onload = function(){
  groupByFirst(document.getElementById('table1'));
}
table {
  border-collapse: collapse;
  border-left: 1px solid #bbbbbb;
  border-top: 1px solid #bbbbbb;
}
th, td {
  border-right: 1px solid #bbbbbb;
  border-bottom: 1px solid #bbbbbb;
}
.toggleButton {
  float: right;
}
.hiddenRow {
  display: none;
}
<table id="table1">
  <tr id="tr1">
    <th>Parent ID</th>
    <th>Parent Name</th>
    <th>Study</th>
  </tr>
  <tr id="tr2">
    <td>1111</td>
    <td>Angela</td>
    <td>XRAY</td>
  </tr>
  <tr id="tr3">
    <td>2222</td>
    <td>Bena</td>
    <td>Ultrasound</td>
  </tr>
  <tr id="tr4">
    <td>3333</td>
    <td>Luis</td>
    <td>CT Scan</td>
  </tr>
  <tr id="tr5">
    <td>1111</td>
    <td>Angela</td>
    <td>Ultrasound</td>
  </tr>
  <tr id="tr6">
    <td>3333</td>
    <td>Luis</td>
    <td>LCD</td>
  </tr>
  <tr id="tr7">
    <td>3333</td>
    <td>Luis</td>
    <td>LASER</td>
  </tr>
</table>