如何动态生成表并对行进行分组

Posted

技术标签:

【中文标题】如何动态生成表并对行进行分组【英文标题】:How to generate a table dynamically and group rows 【发布时间】:2019-11-24 02:52:36 【问题描述】:

我想根据 JSON 响应在数据表中生成数据。以下是我的 JSON 响应:


  "alertItems": [
    
      "id": "PROD-115388",
      "errors": [
       "Original Estimate is null",
       "id is null"          
      ],
      "warnings": [
        "Original Estimate is above threshold",
        "Story points are above threshold",
        "These sub tasks are not defined."
      ]
    ,
    
      "id": "PROD-112479",
      "errors": [],
      "warnings": [
        "Original Estimate is above threshold",
        "Story points are above threshold",
        "Estimate is missing for these sub tasks : PROD-112329"
      ]
    ,
    
      "id": "PROD-108461",
      "errors": [],
      "warnings": [
        "Original Estimate is above threshold",
        "Story points are above threshold",
        "These sub tasks are not defined : Test Case, BA Documentation Task, QA Design and Execute Task, BA/QA/Dev, BA Testing Task, QA Documentation Task, Elaboration"
      ]
    
  ],
  "numberOfErrors": 0,
  "numberOfWarnings": 10

我想生成如下表:

我有一系列警告和错误。我想针对其 ID 为每个警告/错误生成一行。我怎样才能在 jQuery datatables 中做到这一点?

【问题讨论】:

请查看此线程中的示例代码,它可能会对您有所帮助:datatables.net/forums/discussion/32107/… 【参考方案1】:

您可以使用ajax.dataSrc 选项指定将您的数据转换为所需格式的回调函数:

const transform = data => 
    data.alertItems
        .map((id, errors, warnings) => 
            [...errors.map(error => (id, type: 'error', reason: error)),
            ...warnings.map(warning => (id, type: 'warning', reason:warning))])
        .flat();

为了通过匹配第一列中的 id 来对表格行进行分组,您可以使用drawCallback 函数中设置的rowspan html 属性(为此,您需要确保您的表格行排序顺序是固定的,因此具有相同 id 的项目将按顺序排列,而不管排序/过滤)。

因此,完整的示例(注释掉 ajax 部分,因为它在 live sn-p 中不可用)可能看起来像:

//original JSON
const srcJSON = "alertItems":["id":"PROD-115388","errors":["Original Estimate is null","id is null"],"warnings":["Original Estimate is above threshold","Story points are above threshold","These sub tasks are not defined"],"id":"PROD-112479","errors":[],"warnings":["OriginalEstimateisabovethreshold","Storypointsareabovethreshold","Estimateismissingforthesesubtasks: PROD-112329"],"id":"PROD-108461","errors":[],"warnings":["OriginalEstimateisabovethreshold","Storypointsareabovethreshold","Thesesubtasksarenotdefined: TestCase, BADocumentationTask, QADesignandExecuteTask, BA/QA/Dev, BATestingTask, QADocumentationTask, Elaboration"]],"numberOfErrors":0,"numberOfWarnings":10;

//proper JSON
const transform = data => data.alertItems.map((id, errors, warnings) => [...errors.map(error => (id, type: 'error', reason: error)),...warnings.map(warning => (id, type: 'warning', reason:warning))]).flat();

//datatables init
$('table').DataTable(
/*
  ajax: 
    url: //url to API endpoint returning original JSON
    method: //http method (GET, POST, etc)
    dataSrc: transform(data)
  
*/
  data: transform(srcJSON),     //this one should be dropped once ajax section uncommented
  paging: false,
  orderFixed: [0,'asc'],
  columns: [
    data: 'id', title: 'Story Id',
    data: 'type', title: 'Type',
    data: 'reason', title: 'Warning Reason'
  ],
  //group by first col, using rowspan attribute
  drawCallback: function()
	//clean up the view
	$('tbody td').attr('rowspan',1).show();
	//grab datatable into variable
	const table = this.api();
	//grab visible, sorted table rows
	const rows = table.rows(search:'applied',order:'current').nodes();
	var groupIdTd = null;
	//run through the table rows and set 'rowspan' attribute for matching id's
	$.each(rows, function(idx)
		const rowspan = Number($(groupIdTd).attr('rowspan') || 1);
		idx > 0 && table.cell(groupIdTd).data() == table.cell(this,0).data() ?
		($(groupIdTd).attr('rowspan', rowspan+1), $(table.cell(this,0).node()).hide()) :
		(groupIdTd = table.cell(this,0).node(), $(groupIdTd).attr('rowspan',1));
	);
  
)
<!doctype html>
<html>
<head>
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/rg-1.1.0/datatables.min.css" />
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/rowgroup/1.1.0/css/rowGroup.dataTables.min.css" />
  <script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/rg-1.1.0/datatables.min.js"></script>
  <script type="application/javascript" src="https://cdn.datatables.net/rowgroup/1.1.0/js/dataTables.rowGroup.min.js"></script>
  <script src="test.js"></script>
</head>
<body>
 <table></table>
</body>
</html>

【讨论】:

【参考方案2】:

解决方案是在使用ajax.dataSrc 选项将数据传递给DataTables 之前对其进行转换。该解决方案的另一个组件是第三方 rowsGroup 扩展,它允许对具有相同数据的行进行分组。

var table = $('#example').DataTable(
   'ajax': 
      'url': 'https://api.myjson.com/bins/1b72lv',
      'dataSrc': function ( data ) 
         var resultData = [];

         if(data.hasOwnProperty('alertItems'))
            $.each(data.alertItems, function( index, record ) 
               $.each(record.errors, function( index, message ) 
                  resultData.push([ record['id'], 'Error', message ]);
               );

               $.each(record.warnings, function( index, message ) 
                  resultData.push([ record['id'], 'Warning', message ]);
               );
            );
         

         return resultData;
      
   ,
   'rowsGroup': [0]
);   

有关代码和演示,请参阅this example。

有关 rowsGroup 扩展的更多详细信息,请参阅 jQuery DataTables: ROWSPAN in table body TBODY。

【讨论】:

@U25lYWt5IEJhc3RhcmQg,我同意,您的数据转换解决方案更优雅,虽然我不确定设置 rowspan 属性。 @U25lYWt5IEJhc3RhcmQg,更新了答案以摆脱单独的 Ajax 调用并让 DataTables 处理它,非常好!

以上是关于如何动态生成表并对行进行分组的主要内容,如果未能解决你的问题,请参考以下文章

基于动态选择启用文本框并对文本框应用验证

使用带有多个数据源的 IIF 进行动态分组

js 根据数组分组动态生成table(相同项合并)

使用函数动态生成查询

AOP动态代理之CGLIB代理

如何在 Matlab 中使用默认或动态生成的文件名进行保存? [复制]