【问题标题】:How to group child rows in Datatables如何在数据表中对子行进行分组
【发布时间】:2021-07-14 00:54:09
【问题描述】:

我有一个使用子行的表,其中每一行都是可展开/可折叠的,但我的父行会有重复的数据。

我想对我的子行或子行进行分组,因为它们在官方 Datatables 文档中被称为,我有下表,其中父行中有采购订单、采购订单日期、货币和状态列。

如果你看,我有 3 个采购订单对应于这个例子中相同的标识符是 258,但是每个采购订单都包含一个带有不同信息的辅助行,该信息是 Receipt Date,No . 发票、项目代码和描述。

+-----------------------------------------------------------------------+
|    | Purchase Order   |    Purchase Order Date   |Currency|   Status  |
+----+------------------+--------------------------+--------+-----------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |                                
+------+---------+------------+--------------------+-------------+------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+------+---------+-----------+---------------------+-------------+------+
|       07/01/2020      |     617     |      CA0033     |       CT      |
+-----------------------------------------------------------------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|     Receipt Date      | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       14/01/2020      |     620     |      CA0036     |      CTR      |
+-----------------------+-------------+-----------------+---------------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |
+-----------------------+--------------------------+--------+-----------+
|      Receipt Date     | No. Invoice |    Code Item    |  Description  |
+-----------------------+-------------+-----------------+---------------+
|       16/01/2020      |     626     |      CC0048     |      CTY      |
+-----------------------+-------------+-----------------+---------------+

在不重复采购订单的情况下,我想要实现的是按如下方式对辅助行进行分组。

+-----------------------------------------------------------------------+
|    | Purchase Order   |    Purchase Order Date   |Currency|   Status  |
+----+------------------+--------------------------+--------+-----------+
|  + |        258       |       06/01/2020         |   USD  | Delivered |                                
+------+---------+------------+-------------------+-------------+-------+
|      Receipt Date     | No. Invoice |    Code Item    |  Description  |
+------+---------+-----------+--------------------+-------------+-------+
|       07/01/2020      |     617     |      CA0033     |       CT      |
+-----------------------+-------------+-----------------+---------------+
|       14/01/2020      |     620     |      CA0036     |      CTR      |
+-----------------------+-------------+-----------------+---------------+
|       16/01/2020      |     626     |      CC0048     |      CTY      |
+-----------------------+-------------+-----------------+---------------+

如果您现在查看采购订单,它包含组合在一起的相同 3 个订单的信息,这就是我想要的。

以下是我用来构建表格的 AJAX 调用代码。

/* Formatting function for row details - modify as you need */
function format(d) {
    // `d` is the original data object for the row
    console.log(d);
    
    return '<table cellpadding="5" cellspacing="0" style="border-collapse: separate; border-spacing: 40px 5px;">' +
        '<tr>' +      
        '<td><strong>Receipt Date: </strong></td>' + '<td><strong>No. Invoice:<strong></td>' +  '<td><strong>Code Item:<strong></td>' +  '<td><strong>Description:</strong></td>' +
        '</tr>' +
        '<tr>' +
        '<td>' + d.ReceiptDate + '</td>' + '<td>' + d.Invoice+ '</td>' + '<td>' + d.CodeItem+ '</td>' +  '<td>' + d.Description + '</td>' +
        '</tr>' +    
        '</table>';     
}


$(document).ready(function () {
    $('#example').dataTable( {
        responsive : true,
         ajax : {
             "type": 'POST',
             "url" : './test.php',  
             "dataType": 'JSON',             
             "cache": false,
             "data": {
                 'param' : 1,                           
             },
         },
         language : {
            "lengthMenu": "Mostrar _MENU_ registros",
            "zeroRecords": "No se encontró nada",
            "info": "Mostrando del _START_ al _END_ de un total de _TOTAL_",
            "infoEmpty": "No hay registros",
            "emptyTable": "No hay datos para mostrar",
            "loadingRecords": "Cargando...",
            "processing": "Procesando...",
            "search": "Buscar:",
            "infoFiltered": "(filtrado de un total de _MAX_ registros)",
            "paginate": {
                "first": "Primera",
                "last": "Última",
                "next": "Siguiente",
                "previous": "Anterior"
            }
         },    
         columns: [          
             {
                 "className":      'details-control',
                 "orderable":      false,
                 "data":           null,
                 "defaultContent": ''
             },
             { "data" : "PurchaseOrder" },
             { "data" : "PurcharOrderDate" },
             { "data" : "Currency" },
             { "data" : "Status" }                 
        ],
         order : [[1, 'desc']]
    } );

    
    // Add event listener for opening and closing details
    $('#example').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = $('#example').DataTable().row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        }
    });

});

查阅Datatables 文档,它有一个RowGroup 扩展名,但我不知道它们是否可以分组为子行或子行。如果您能帮助我找到解决此问题的方法,我将不胜感激。

更新:

下面我按照评论中的要求对 test.php 提供的 JSON 响应进行非规范化,这样做的目的是为了访问每个子行所需的所有数据。

[
  {
    "Purchase Order": 949,
    "Purchase Order Date": "20/11/2019",
    "Receipt Date": "12/12/2019",
    "No. Invoice": 448,
    "Code Item": "CC0048",
    "Description": "CTR",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 949,
    "Purchase Order Date": "20/11/2019",
    "Receipt Date": "13/12/2019",
    "No. Invoice": 448,
    "Code Item": "CC0048",
    "Description": "CTR",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 949,
    "Purchase Order Date": "20/11/2019",
    "Receipt Date": "14/12/2019",
    "No. Invoice": 448,
    "Code Item": "CC0048",
    "Description": "UBC",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 949,
    "Purchase Order Date": "20/11/2019",
    "Receipt Date": "15/12/2019",
    "No. Invoice": 448,
    "Code Item": "CC0048",
    "Description": "UBC",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 258,
    "Purchase Order Date": "05/12/2019",
    "Receipt Date": "17/12/2019",
    "No. Invoice": 451,
    "Code Item": "CA0033",
    "Description": "CTY",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 258,
    "Purchase Order Date": "05/12/2019",
    "Receipt Date": "18/12/2019",
    "No. Invoice": 451,
    "Code Item": "CA0033",
    "Description": "CTY",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 258,
    "Purchase Order Date": "05/12/2019",
    "Receipt Date": "19/12/2019",
    "No. Invoice": 452,
    "Code Item": "CA0033",
    "Description": "CTY",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 258,
    "Purchase Order Date": "05/12/2019",
    "Receipt Date": "20/12/2019",
    "No. Invoice": 452,
    "Code Item": "CA0033",
    "Description": "CTY",
    "Status": "Delivered",
    "Currency": "USD"
  },
  {
    "Purchase Order": 258,
    "Purchase Order Date": "05/12/2019",
    "Receipt Date": "21/12/2019",
    "No. Invoice": 452,
    "Code Item": "CA0033",
    "Description": "CTY",
    "Status": "Delivered",
    "Currency": "USD"
  }
]

重要的是要记住,作为父行,我需要采购订单、采购订单日期、货币和状态,而作为子行,我需要找到收货日期、发票编号、代码项目和描述。

更新 2:

我添加了 php 代码来为我的问题提供更多指导。

Test.php

<?php
    header('Content-Type: text/html; charset=utf-8');
    
    $param = $_POST['param'];   
    switch($param) {
        case '1': 
                $query = array();
                include './db/conecct.php';
                $sql = "select PURCHID as 'PurchaseOrder',
                CREATEDDATETIME as 'PurchaseOrderDate',
                MONEDA as 'Currency',
                INVOICEDATE as 'ReceiptDate',
                ITEMID  as 'CodeItem',
                FACTURA as 'No. Invoice',
                NAMEALIAS as 'Description',
                PURCHSTATUS as 'Status'         
                FROM PP_FACTURAS
                $stmt = sqlsrv_query($conn, $sql, $params);
                if ( $stmt === false) {
                    die( print_r( sqlsrv_errors(), true) );
                }   
                while( $row = sqlsrv_fetch_array($stmt) ) {
                    //print_r($row);
                    $record = array(
                       "PurchaseOrder"       => $row['PurchaseOrder'],
                       "PurchaseOrderDate"  => $row['PurchaseOrderDate']->format('d/m/Y'),
                       "Currency"        => $row['Currency'],
                       "Status"            => $row['Status'],
                       "PurchaseOrderDate"      => $row['PurchaseOrderDate'] != null ? $row['PurchaseOrderDate']->format('d/m/Y'):"",
                       "No. Invoice"           => utf8_encode ($row['No. Invoice']),
                       "CodeItem"          => utf8_encode ($row['CodeItem']), 
                       "Description"        => utf8_encode ($row['Description']),           
                    );
                    array_push($query, $record);
                }

                sqlsrv_free_stmt( $stmt);       
                sqlsrv_close($conn);

                $json = array(
                    "success"=> count($query) > 0 ? true : false,
                    "data"=>$query
                );

                echo json_encode($json);
            break;

更新 3:

尝试回答,现在我在控制台中收到以下错误:

Uncaught TypeError: originalJson is not iterable

我根据答案附上我支持自己的代码:

/* Formatting function for row details - modify as you need */
function format(d) {
    // `d` is the original data object for the row
    console.log(d);

    var tableHtml = '<table><thead><tr><th>Receipt Date</th><th>Invoice No.</th><th>Item Code</th><th>Description</th></tr></thead>';

       tableHtml = tableHtml + '<tbody>';

        var rowHtml = '';
        for (const rowData of d.details){
            rowHtml = rowHtml + '<tr><td>' + rowData.ReceiptDate + '</td><td>' + rowData.Invoice + '</td><td>' + rowData.CodeItem + '</td><td>' + rowData.Description + '</td></tr>';
        }
        tableHtml = tableHtml + rowHtml + '</tbody></table>';
        return tableHtml;
}


function denormalize(originalJson) {
    let denormalizedMap = new Map();

    for (const element of originalJson) {
        let headerInfo = (({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }) => ({
            PurchaseOrder,
            PurcharOrderDate,
            Currency,
            Status
        }))(element);
        headerInfo.details = [];

        let detailLine = (({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description

        }) => ({
            ReceiptDate,
            Invoice,
            CodeItem,
            Description
        }))(element);

        if (! denormalizedMap.has(element.PurchaseOrder)) {
            denormalizedMap.set(element.PurchaseOrder, headerInfo);
        }
        denormalizedMap.get(element.PurchaseOrder).details.push(detailLine);
    }

    let denormalizeSource = Array.from(denormalizedMap.values());

    return denormalizeSource;
}

$(document).ready(function () {
    $('#example').dataTable( {
        responsive : true,
         ajax : {
             "type": 'POST',
             "url" : './test.php',  
             "dataType": 'JSON',             
             "cache": false,
             "dataSrc" : function (json){
                 console.log(json);
                 return denormalize(json);
             },
         },    
         columns: [          
             {
                 "className":      'details-control',
                 "orderable":      false,
                 "data":           null,
                 "defaultContent": ''
             },
             { "data" : "PurchaseOrder" },
             { "data" : "PurcharOrderDate" },
             { "data" : "Currency" },
             { "data" : "Status" }                
     
        ],
         order : [[1, 'desc']],
    } );

    
    // Add event listener for opening and closing details
    $('#example').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var row = $('#example').DataTable().row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        }
    });

});

【问题讨论】:

  • 您可以将 DataTables 的“子”行视为已经是父行的源数据对象一部分的额外数据。在构建子对象时,您只能访问该一个源对象(因此代码中的注释:“d 是原始数据对象for the row”)。您可以首先对test.php 提供的 JSON 响应进行非规范化(或使用 JavaScript 对其进行后处理),以访问每个子行所需的所有数据。然后,d 将包含您需要的所有数据。这也同时解决了“重复父行”问题(没有重复的 PO 行)。
  • @andrewjames 您可以查看我的上次更新添加我处理的 JSON 文件,以便您可以访问每行中的数据
  • 我认为这里对“非规范化”的含义存在误解。您问题中的示例数据每个唯一的采购订单号没有一个对象。每个唯一的 PO 仍然有许多对象。所以,这对你没有帮助。我不使用 PHP,但如果有帮助,我可以向您展示使用 JS 的意思。
  • @andrewjames 我明白了,告诉我你说的 JS 是什么意思,这对我有很大帮助

标签: javascript jquery ajax datatables


【解决方案1】:

根据最初的问题,我假设您的 ajax 调用提供的 JSON 如下所示:

[
  { "PurchaseOrder": 258,
    "PurcharOrderDate": "06/01/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "ReceiptDate": "07/01/2020",
    "Invoice": 617,
    "CodeItem": "CA0033",
    "Description": "CT"
  },
  { "PurchaseOrder": 258,
    "PurcharOrderDate": "06/01/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "ReceiptDate": "04/01/2020",
    "Invoice": 620,
    "CodeItem": "CA0036",
    "Description": "CTR"
  },
  { "PurchaseOrder": 258,
    "PurcharOrderDate": "06/01/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "ReceiptDate": "16/01/2020",
    "Invoice": 626,
    "CodeItem": "CA0048",
    "Description": "CTY"
  },
  { "PurchaseOrder": 261,
    "PurcharOrderDate": "22/02/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "ReceiptDate": "03/03/2020",
    "Invoice": 679,
    "CodeItem": "CA0062",
    "Description": "CTZ"
  }
];

我为 PO 编号 261 添加了一个额外的行,只是为了使数据更加多样化。

您希望将其重组为一个新数组,其中每个唯一的采购订单号只有一个对象(但该对象还包含相关发票记录的多个项目)。

以下数据实现了这一点:

[
  {
    "PurchaseOrder": 258,
    "PurcharOrderDate": "06/01/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "details": [{
      "ReceiptDate": "07/01/2020",
      "Invoice": 617,
      "CodeItem": "CA0033",
      "Description": "CT"
    },
    {
      "ReceiptDate": "04/01/2020",
      "Invoice": 620,
      "CodeItem": "CA0036",
      "Description": "CTR"
    },
    {
      "ReceiptDate": "16/01/2020",
      "Invoice": 626,
      "CodeItem": "CA0048",
      "Description": "CTY"
    }]
  },
  {
    "PurchaseOrder": 261,
    "PurcharOrderDate": "22/02/2020",
    "Currency": "USD",
    "Status": "Delivered",
    "details": [{
      "ReceiptDate": "03/03/2020",
      "Invoice": 679,
      "CodeItem": "CA0062",
      "Description": "CTZ"
    }]
  }
]

现在数组中只有 2 个对象(因为只有 2 个唯一的采购订单编号) - 但每个对象都包含一个 details 子数组,其中包含相关采购订单编号的行项目详细信息。

现在您有了可以在 DataTable 中使用的数据。该表将显示 2 条记录,您可以从子数组中为每个 DataTable "child" 构建一个子表。

这里有一个 Fiddle 显示完整的细节,包括 JavaScript 重组代码:

https://jsfiddle.net/ztu2ar0h/

它缺少实际获取 ajax 数据所需的 URL,因此它不会运行。 (而且它缺少用于打开和关闭子行的图标。)但其他一切都在那里。


更新

回应 cmets 的回答:

您的 PHP 代码连接到您的数据库,运行查询,然后构建 JSON 响应,并使用 echo json_encode($json) 将其发送到 DataTables。

您实际上并没有我们展示 JSON 的样子。但就像我在回答开头所说的那样,我对它的外观做了一个假设 - 我向你展示了假设 JSON。

这是您的 PHP 代码通过 DataTable 的 ajax 调用传递给 DataTable 的内容。

所以,我在回答中所做的只是获取 JSON(从 PHP 发送到 DataTable),然后将其重新排列成更有用的结构。我正在 DataTable 的 ajax 调用中重新安排:

ajax: {
  method: "GET",
  url: // your URL goes here!,
  dataSrc: function ( json ) { 
    //console.log( json );
    return restructure(json);
  },
},

所以,我不是使用 PHP 代码中的原始 JSON,而是首先重新排列原始 JSON,使用上面的 JavaScript 代码,它使用我的 restructure() 函数。

这个重新排列的 JSON 是 DataTables 用来构建表格的。

就是这样。真的就这么简单。

但就像我说的 “我不使用 PHP,但我可以告诉你我使用 JS 的意思”。这就是我在 Fiddle 中所做的。

所以,如果您不想使用上述方法,欢迎您使用我的restructure(json) 函数并将其重写为 PHP 代码。然后,您可以自己在 Test.php 文件中重新安排原始 JSON - 您可以将 重组 JSON 从 PHP 文件传递​​到 DataTable。

您想采用哪种方法取决于您。他们都做同样的事情。

(在这两种方法中,任何地方都没有 JSON 文件。)

【讨论】:

  • 我看到你在这里使用它和一个 JSON 文件,我这样做了,但是对于我的真实代码,我使用数据库查询,因为数据是从那里获得的,所以可以这样做使用数据库查询
  • 我以 JSON 文件为例,因为从这里我无法直接连接到我的数据库,但基本上是相同的数据
  • 不,我没有使用 JSON 文件。我使用了一个 ajax 查询,和你一样。
  • 显然你的答案对我不起作用,因为它是从我的原始代码中的 JSON 文件获得的数据,我使用数据库连接。我看到自己需要添加我的PHP代码以便可以遍历所有数据,您可以查看我的上次更新。
  • 您为什么认为我的数据来自 JSON 文件? (不是。)
猜你喜欢
  • 2021-02-11
  • 1970-01-01
  • 2019-07-16
  • 1970-01-01
  • 2015-09-18
  • 2020-08-16
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多