PDF output of grouped rows is messed up
PDF output of grouped rows is messed up
dnagirl
Posts: 36Questions: 2Answers: 0
Hi,
I've got a table that I'm grouping on the 1st column. I'm dynamically adding [code]{group Name}{ytd subtotal}{cur value[/code] for the grouping rows. I've also added a Totals row to the footer. The table works and looks great in the browser. But when I hit the PDF button, the "hidden" column[0] data overprints the column[1] data making it unreadable and all the subtotal and total rows are missing. What do I need to do? Optimally, I'd like the pdf to look exactly like the browser output.
Here's my setup:
[code]
var oTable=$('.datatable').dataTable( {
"fnDrawCallback": function ( oSettings ) {
if(oSettings.aiDisplay.length == 0) return;
var nTrs = $('.datatable tbody tr');
$(nTrs).removeData();//so that subtotals from different draws are not summed
var iColspan = nTrs[0].getElementsByTagName('td').length -2;//need 2 columns for the subtotals
var sLastGroup = "";
$(nTrs).each(function(i){
$('td:first',this).css('padding-left','2em');//indent the strain names
var iDisplayIndex = oSettings._iDisplayStart + i;
var sGroup = oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[0];
if($(nTrs).data()[sGroup] === undefined) $(nTrs).data()[sGroup]={'ytd':0,'cur':0};
$(nTrs).data()[sGroup].ytd += parseFloat(oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[2]); //subtotal ytd
$(nTrs).data()[sGroup].cur += parseFloat(oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[3]);//subtotal cur
if(sGroup != sLastGroup){
var nGroup = $('').addClass('group');
var nCell = $(''+sGroup+'' ).attr('colspan',iColspan);
var nProdTot = $('').addClass('ytd');
var nCurTot = $('').addClass('cur');
$(nGroup).append(nCell,nProdTot,nCurTot);
$(this).before(nGroup);
sLastGroup = sGroup;
}
});
for(var g in $(nTrs).data()){
var nSTot=$('.datatable tbody tr.group').has('th:contains("'+ g +'")');
$('th.ytd',nSTot).append($(nTrs).data()[g].ytd);
$('th.cur',nSTot).append($(nTrs).data()[g].cur);
}
},
"fnFooterCallback":function(nRow, aasData, iStart, iEnd, aiDisplay ){
if(0==parseInt(iEnd)) return;
fnTots=function(iColnum){
var total=0;
for(var i=iStart;i
Foo
AB wt
6
20
Bar
Tub wt
43
0
Bar
Ztag
1
74
Bar
KDR-eGFP
17
33
Foo
BTTP6.2-Luc
2
1
Foo
Tg(hsp70tolgfp)v28
354
786
[/code]
I've got a table that I'm grouping on the 1st column. I'm dynamically adding [code]{group Name}{ytd subtotal}{cur value[/code] for the grouping rows. I've also added a Totals row to the footer. The table works and looks great in the browser. But when I hit the PDF button, the "hidden" column[0] data overprints the column[1] data making it unreadable and all the subtotal and total rows are missing. What do I need to do? Optimally, I'd like the pdf to look exactly like the browser output.
Here's my setup:
[code]
var oTable=$('.datatable').dataTable( {
"fnDrawCallback": function ( oSettings ) {
if(oSettings.aiDisplay.length == 0) return;
var nTrs = $('.datatable tbody tr');
$(nTrs).removeData();//so that subtotals from different draws are not summed
var iColspan = nTrs[0].getElementsByTagName('td').length -2;//need 2 columns for the subtotals
var sLastGroup = "";
$(nTrs).each(function(i){
$('td:first',this).css('padding-left','2em');//indent the strain names
var iDisplayIndex = oSettings._iDisplayStart + i;
var sGroup = oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[0];
if($(nTrs).data()[sGroup] === undefined) $(nTrs).data()[sGroup]={'ytd':0,'cur':0};
$(nTrs).data()[sGroup].ytd += parseFloat(oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[2]); //subtotal ytd
$(nTrs).data()[sGroup].cur += parseFloat(oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData[3]);//subtotal cur
if(sGroup != sLastGroup){
var nGroup = $('').addClass('group');
var nCell = $(''+sGroup+'' ).attr('colspan',iColspan);
var nProdTot = $('').addClass('ytd');
var nCurTot = $('').addClass('cur');
$(nGroup).append(nCell,nProdTot,nCurTot);
$(this).before(nGroup);
sLastGroup = sGroup;
}
});
for(var g in $(nTrs).data()){
var nSTot=$('.datatable tbody tr.group').has('th:contains("'+ g +'")');
$('th.ytd',nSTot).append($(nTrs).data()[g].ytd);
$('th.cur',nSTot).append($(nTrs).data()[g].cur);
}
},
"fnFooterCallback":function(nRow, aasData, iStart, iEnd, aiDisplay ){
if(0==parseInt(iEnd)) return;
fnTots=function(iColnum){
var total=0;
for(var i=iStart;i
Foo
AB wt
6
20
Bar
Tub wt
43
0
Bar
Ztag
1
74
Bar
KDR-eGFP
17
33
Foo
BTTP6.2-Luc
2
1
Foo
Tg(hsp70tolgfp)v28
354
786
[/code]
This discussion has been closed.
Replies
[code]
'aButtons':[
{
'sExtends':'csv',
'mColumns':'visible'
},
{
'sExtends':'copy',
'mColumns':'visible'
},
{
'sExtends':'pdf',
'mColumns':'visible'
},
{
'sExtends':'print',
'mColumns':'visible'
}
[/code]
Allan
That jsbin may also have access difficulties because the TableTools file I've referred to is on my server rather than yours. For some reason the TableTools available from your site complains that
[quote]
Message: 'ZeroClipboard' is undefined
Line: 36 //line 1147 in TableTools.js
Char: 135
Code: 0
URI: http://datatables.net/download/build/TableTools.min.js
[/quote]
as can be seen here: http://live.datatables.net/ucijil/
The pdfs produced by the script on my home server and the one on jsbin are identical. I have not edited the TableTools source file.
So basically the problem you are facing is that you are dynamically deleting and adding TH nodes in the footer. The problem with this is that DataTables keeps a reference to those nodes - so if they disappear, DataTables is still holding a reference to the old ones - not the new ones! Hence why they don't show up in the PDF, you are dynamically adding them, so DataTables doesn't know that there is a footer!
So to address this, just create the TH elements in the table like normal and update them on-the-fly, without deleting the elements. Here is a modification of your example which does export the footer: http://live.datatables.net/ixuneh/20/edit .
Allan
Unfortunately, it doesn't resolve the subtotal issue. I expect the cause is similar? The subtotal rows (ie grouping rows) don't exist/are replaced each time fnDrawCallback is called. I suppose I could add some empty rows to the table for use as grouping rows rather than create them on the fly, but that seems like a brittle solution.
Suggestions?
There is an internal function in TableTools which does the data get ( https://github.com/DataTables/TableTools/blob/master/media/js/TableTools.js#L1493 ) and I suspect that this would need to be modified to include the extra rows by doing a query on the DOM to get all TR rows, and then checking with DataTables if the data is available for each row. If there data is then use it, if not then its a sub-total row and you need to pull the data in from the DOM.
Sorry there isn't an easy option with that one.
Allan
[code] {
'sExtends':'text',
'sButtonText':'Download PDF',
'sAction': 'text',
'bFooter':true,
'bHeader':true,
'fnClick':function(nButton, oConfig, oFlash){
var sFiletext=$('div.dataTables_scroll').html();
$('form#mpdf input[name="pdf_fn"]').val('TT.pdf');//or something dynamic
$('#mpdf textarea[name="pdf_html"]').val(sFiletext);
$('form#mpdf').submit();
}
}[/code]
and a target form like this:
[code]
[/code]
The revised HTML (rather than the pre-DataTable HTML) is submitted to the HTML-to-PDF script (I'm using mPDF: http://mpdf1.com/manual/index.php) which returns a PDF file for download.
It would be nice if I could avoid the invisible form, but this method allows me output exactly what the DataTable is showing without requiring me to somehow build the table anew serverside. I did try to get ajax to work, but no luck. If anyone had an idea how I could avoid the invisible form, I'd love to hear it.