I have a table that makes use of child rows where each row is expandable/collapsible, but my parent rows contain duplicate data as explained below.
I would like to group my secondary rows or child row, as they are called in the official Datatables documentation , where I have the following table where in the parent row there are the Purchase Order, Purchase Order Date, Currency and State columns.
If you look, I have 3 purchase orders that correspond to the same identifier, in this example it is 258 , but each purchase order contains a secondary row with different information, that information is Receive Date, Invoice No., Item Code and Description.
+-----------------------------------------------------------------------+
| | Orden de compra | Fecha de Orden de Compra | Moneda | Estado |
+----+------------------+--------------------------+--------+-----------+
| + | 258 | 06/01/2020 | USD | Entregado |
+------+---------+------------+-------------------+-------------+-------+
| Fecha de recepción | No. Factura | Código Articulo | Descripción |
+------+---------+-----------+--------------------+-------------+-------+
| 07/01/2020 | 617 | CA0033 | CT |
+-----------------------------------------------------------------------+
| + | 258 | 06/01/2020 | USD | Entregado |
+-----------------------+--------------------------+--------+-----------+
| Fecha de recepción | No. Factura | Código Articulo | Descripción |
+-----------------------+-------------+-----------------+---------------+
| 14/01/2020 | 620 | CA0036 | CTR |
+-----------------------+-------------+-----------------+---------------+
| + | 258 | 06/01/2020 | USD | Entregado |
+-----------------------+--------------------------+--------+-----------+
| Fecha de recepción | No. Factura | Código Articulo | Descripción |
+-----------------------+-------------+-----------------+---------------+
| 16/01/2020 | 626 | CC0048 | CTY |
+-----------------------+-------------+-----------------+---------------+
What I would like to achieve without repeating the Purchase Order is to group the child rows as follows.
+-----------------------------------------------------------------------+
| | Orden de compra | Fecha de Orden de Compra | Moneda | Estado |
+----+------------------+--------------------------+--------+-----------+
| + | 258 | 06/01/2020 | USD | Entregado |
+------+---------+------------+-------------------+-------------+-------+
| Fecha de recepción | No. Factura | Código Articulo | Descripción |
+------+---------+-----------+--------------------+-------------+-------+
| 07/01/2020 | 617 | CA0033 | CT |
+-----------------------+-------------+-----------------+---------------+
| 14/01/2020 | 620 | CA0036 | CTR |
+-----------------------+-------------+-----------------+---------------+
| 16/01/2020 | 626 | CC0048 | CTY |
+-----------------------+-------------+-----------------+---------------+
If you look at the Purchase Order now it contains grouped the information of the 3 same orders, this is what I want to get to.
The following is the code for my AJAX call which I use to build my tables.
/* 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>Fecha de Recepción: </strong></td>' + '<td><strong>No. Factura:<strong></td>' + '<td><strong>Codigo Art:<strong></td>' + '<td><strong>Descripcion Art:</strong></td>' +
'</tr>' +
'<tr>' +
'<td>' + d.FechaFactura + '</td>' + '<td>' + d.Factura + '</td>' + '<td>' + d.Codigo + '</td>' + '<td>' + d.Descripcion_Articulo + '</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" : "OrdenCompra" },
{ "data" : "FechaOrdenCompra" },
{ "data" : "TipoMoneda" },
{ "data" : "Estatus" }
],
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');
}
});
});
Consulting the Datatables documentation, it has a RowGroup extension, but I don't know if they can be grouped for secondary rows or child rows. I would be grateful to each of you if you can help me find a way out of this problem.
It is important to remember that, as the main row, I require Purchase Order, Purchase Order Date, Currency and State, and as a secondary row, I need to locate the Receive Date, Invoice No., Item Code and Description.
Update:
I attach a handmade example of what I want to build with my table:
If you look, I have two purchase orders that each contain a sub-row with information. Instead of repeating each of the purchase orders, I group them into one depending on their ID.
In my Javascript it looks like this:
/* Formatting function for row details - modify as you need */
function format(d) {
// `d` is the original data object for the row
console.log(d);
let tabla = `<table cellpadding="5" cellspacing="0" style="border-collapse: separate; border-spacing: 40px 5px;">
<thead>
<tr>
<th>
Fecha de recepción
</th>
<th>
No. Factura
</th>
<th>
Codigo Art
</th>
<th>
Descripcion
</th>
</tr>
</thead>
<tbody>`;
d.Factura.forEach(f => {
tabla += `<tr>
<td>${f.FechaFactura}</td>
<td>${f.Factura}</td>
<td>${f.Codigo}</td>
<td>${f.Descripcion_Articulo}</td>
</tr>`;
});
tabla += '</tbody></table>';
return tabla;
}
When I reload my table I get the following error:
UPDATE 4:
Now I get the following in the response to my JSON:
After trying the last modification to the response I now get the following as a response to my JSON.
UPDATE 5:
I am now getting the following as a response to my JSON
And as alert
when loading the table from the Datatables view I get the following:
UPDATE 6:
After trying the code found in the answer I get a result in the Datatable but all child rows are grouped in a single parent row to avoid this I built the following data to group by parent row and child row.
After while
add the following grouped data:
// -- Aquí tienes toda tu data agrupada
$group_data = group_array($query, "OrdenCompraGroup");
// -- Creamos un nuevo array para la nueva data procesada
$new_data = array();
// -- Vamos armar un array padre e hijo
foreach($group_data as $itemPadre) {
// -- Variables que necesitas para el padre
$ordenCompra = "";
$fechaOrdenCompra = "";
$TipoMoneda="";
$Estatus = "";
// -- Declaramos la variable donde se almacenaran los datos hijos
$arrayFactura = array();
// --
foreach($itemPadre["groupdata"] as $itemHijo) {
// -- Aquí llenamos las variables del padre, ya que se encuentran dentro del groupdata
$ordenCompra = $itemHijo["OrdenCompra"];
$fechaOrdenCompra = $itemHijo["FechaOrdenCompra"];
$TipoMoneda = $itemHijo["TipoMoneda"];
$Estatus = $itemHijo["Estatus"];
// -- Aquí llenamos la data del hijo
$arrayFactura[] = array(
"Factura" => $itemHijo["Factura"],
"FechaFactura" => $itemHijo["FechaFactura"], //Fecha de recepcion,
"Codigo" => $itemHijo["Codigo"],
"Descripcion_Articulo" => utf8_encode ($itemHijo["Descripcion_Articulo"]),
);
}
// -- Aquí llenamos el array general (En este punto tenemos los datos del padre y del hijo)
$new_data[] = array(
"OrdenCompra" => $ordenCompra, // -- PADRE
"FechaOrdenCompra" => $fechaOrdenCompra, // -- PADRE
"TipoMoneda" => $TipoMoneda, //PADRE
"Estatus" => $Estatus,//PADRE
"Factura" => $arrayFactura,//HIJO
);
}
But at this point I run into the problem that the data is not displayed in my Datatable, if it's not one thing it's the other.
It is necessary to change the data structure to group invoices by purchase order, showing only purchase order in the main table and all related invoices in secondary rows.
Instead of generating an element for each invoice, it will be done by purchase order, creating a subarray with the corresponding invoices, thus:
Follow these steps:
ORDER BY OrdenCompra, Factura
to make it easier to create the array.In Javascript you just need to update the function to create the table with its headers and loop through the invoices to fill. Instead of concatenating the HTML, it's easier and more readable to use text templates :
You should have no problem assembling the data if it is obtained sorted from the query. I'm going to give you an example with Javascript with the same logic used in PHP.
Como ves, solo debes asegurarte que los resultados de la consulta tengan el formato y orden adecuado para armar los datos de salida; no es necesario crear otro arreglo para tratar de "componerlo".
One way you can achieve this is by using the
fnOpen
and functionsfnClose
of dataTables, without using the RowGroup extension. Not sure if there is an updated version, these features are in the legacy versionBasically instead of having your child rows added one by one to your main table, you make all the child rows one complete table. Then on your + button you call
fnOpen
and pass the full child table to it.It would be something like this, very similar to what you are doing right now:
If you decide to load it with ajax, you would do it in the else block .
Mis recomendaciones son las siguientes
Puedes pre-serializar la agregación.
Obteniendo desde la base de datos un json formateado con las facturas:
En PHP de-serializas en un segundo nivel:
Para que el AJAX reciba algo como:
Para formatear las filas secundarias:
Well you can get the same thing by doing a PHP query for each purchase order, but if you take care that null values don't affect the json format, you can get it in a single trip to the database.