+ Start a Discussion
JskinJskin 

Splitting datatable in pdf onto separate pages

Hi,

 

My knowledge on coding is very basic so I am not sure it is possble to do what I'd like or if I have to find an alternate solution.   Basically I am rendering a pdf which lists of of the delegates who have attended a training course and stating if they have passed or failed. 

 

I am doing this in a pdf attachment to an email.  I had it working fine until I found a course with 30+ delegates as the table just continues to render over the page footer and beyond.  Is there anyway to easily split this table after 30 entries (I would like to avoid anything creating controllers etc as they are over my head)?

 

This is my code (the red section is the data table):

 

<messaging:attachment renderAs="pdf"  filename="Exam results notification">
<html>
<head><style type="text/css" media="print">
body {color:#666666; font-family:"Arial Unicode MS"; font-size:11pt; font-style:normal; }

@page{
    @bottom-left {                  
    content: element(footer);      
    }   
    size: A4 portrait;
    margin-top:0cm;
    margin-left:0cm;
    margin-right:0cm;
    margin-bottom:0cm;  
}

div.footer {
   display: block;
   position: running(footer);
   line-height: 10pt;
   font-size: 7.5pt;
   color: #A9A9A9;
   z-index:2;                
}
   
</style>
</head>

<body>


<img src="{!URLFOR($Resource.Template)}" style="position: fixed; left: 0cm; top: 0cm;  z-index:-2;" width="21cm" height="29.7"/>

 <apex:dataTable cellpadding="2" width="15.92cm" border="0.2" style=" text-align:center; position: fixed; left: 2.54cm; top: 8cm; line-height: 12pt; font-size:11pt; z-index:+2;" columns="5" value="{!relatedTo.Enrollments__r}" var="cx" >

               <apex:column width="3cm"  >  
                   <apex:facet name="header">Number</apex:facet>
                       {!cx.name}       
               </apex:column>
               <apex:column >
                      <apex:facet name="header">姓名</apex:facet>
                             {!cx.delegate_name__r.LastNameLocal}{!cx.delegate_name__r.FirstNameLocal}
               </apex:column>
               <apex:column >
                      <apex:facet name="header">單位</apex:facet>
                          {!cx.delegate_name__r.department}     
               </apex:column>
               <apex:column >
                     <apex:facet name="header">英文姓名</apex:facet>
                         {!cx.delegate_name__r.LastName}{!cx.delegate_name__r.FirstName}
               </apex:column>
               <apex:column width="2cm" >
                   <apex:facet name="header">Pass/Fail</apex:facet>
                       {!IF(OR(CONTAINS(cx.Exam_results__c,'Fail'),CONTAINS(cx.Exam_results__c,'fail')),'F','P')}
               </apex:column>
               
        </apex:dataTable>



<table width="15.92cm" valign="top" style="position: fixed; left: 2.54cm; top: 27.1cm; line-height: 10pt; font-size:7.5pt; color: #A9A9A9;" >
  <colgroup>
    <col span="4" width="3.98cm" />
  </colgroup>
<tr valign="top">
<td>
address
</td>
<td>address</td>
<td></td>
<td></td>
</tr>
</table>
</body></html>
</messaging:attachment>

 

Many Thanks for any help you can offer.

 

Best Answer chosen by Admin (Salesforce Developers) 
JskinJskin

 

Hi,

 

Just for information.  I managed to achieve what I wanted using the following:

 

<messaging:attachment renderAs="pdf"  filename="Exam results notification">
<html>
<head><style type="text/css" media="print">
body {color:#666666; font-family:"Arial Unicode MS"; font-size:11pt; font-style:normal;}

@page{
    @bottom-left {                 
    content: element(footer);     
    }
    @top-right {
    content: "Page " counter(page) " of " counter(pages);
    font-family:"Arial Unicode MS";
    font-size:11pt;
    }
    @top-left-corner {
    content: element(header);
    }
    size: A4 portrait;
    margin-top:5cm;
    margin-left:2.54cm;
    margin-right:2.54cm;
    margin-bottom:5cm; 
}

table {
    -fs-table-paginate: paginate;
    }
 

div.footer {
   display: block;
   padding: 10px;                      
   position: running(footer);
   line-height: 10px;
   z-index: 3;
   color: #A9A9A9;
   font-family:"Arial Unicode MS";
   font-size:7.5pt;
              
}

div.header {
   display: block;                     
   position: running(header);
               
}
 
</style>
</head>

<div class="header" >
    <table table-layout="fixed">
    <img src="{!URLFOR($Resource.Document_Logo)}" width="21cm" height="28.7"/>
    </table>
</div>

<div class="footer" >
  <table width="15.92cm" style="left: 2.54cm; top: 27.1cm; line-height: 10pt;" align="left" valign="top" table-layout="fixed">
<tr valign="top">
<td>
address
</td>
</tr>
</table>
</div>

<body>

<table cellpadding="3" cellspacing="0" styleclass="table" width="15cm" border="0.1" style="left: 2.54cm; text-align:center; font-size:11pt;">
        <THEAD>
            <tr>
                <th style="border:1px solid #000000;border-right:0;">Number</th>
                <th style="border:1px solid #000000;border-right:0;">姓名</th>
                <th style="border:1px solid #000000;border-right:0;">單位</th>
                <th style="border:1px solid #000000;border-right:0;">英文姓名</th>
                <th style="border:1px solid #000000;">Pass/Fail</th>
            </tr>
        </THEAD>
            <apex:repeat value="{!relatedTo.Enrollments__r}" var="cx">
        <TBODY>
            <tr>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.name}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.LastNameLocal}{!cx.delegate_name__r.FirstNameLocal}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.department}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.LastName}{!cx.delegate_name__r.FirstName}</td>
                <td style="border:1px solid #000000;border-top:0;">{!IF(OR(CONTAINS(cx.Exam_results__c,'Fail'),CONTAINS(cx.Exam_results__c,'fail')),'F','P')}</td>
            </tr>
        </TBODY>
        </apex:repeat>
</table>
</body>
</html>
</messaging:attachment>

 

  • I changed the datatable to the code above to produce a table with a single line border around the full table and cells. 
  • Using the  -fs-table-paginate: paginate I got the table with the column headings on each page. 
  • Using the margins on the @page I managed to limit the amount of data shown on each page.
  • And finally using content: element(footer) and content: element(header) I suceeding in showing the correct logo and footer on each page.   

Took a bit longer than I hoped but will be able to reuse this again in future!.

 

 

 

All Answers

sfdcfoxsfdcfox

You should use css media selectors related to using tbody and thead, something like this:

 

http://stackoverflow.com/questions/274149/css-repeat-table-headers-in-print-mode

 

Note that salesforce.com is using Flying Saucer for its PDF rendering.

 

Some other helpful notes:

 

http://stackoverflow.com/questions/10512324/css-to-pdf-the-css-in-flying-saucer-fs-table-paginate-result-in-border-collap

 

http://www.w3.org/TR/html4/struct/tables.html#edef-THEAD

 

 

JskinJskin

Thanks so much sfdcfox,

 

I've moved forward a step in that I can get the table breaking over the pages and with the headers on each page by adding in:

 

      table { -fs-table-paginate: paginate; }

 

to my style sheet and changing the datatable to:

 

       <apex:dataTable cellpadding="2" styleclass="table" width="15.92cm" border="0.2" style="text-align:center; line-height: 12pt; font-size:11pt;" columns="5" value="{!relatedTo.Enrollments__r}" var="cx" >

 

I needed to remove the position: fixed part to make it work. However I now need to position the table nicely on the page. I tried position: relative but this stopped the headers appearing on each page.

 

Has anyone any further suggestions..... Many Thanks.

sfdcfoxsfdcfox

You'll probably need to use a padding or margin attribute. You can't have a table that's both positioned and running (at least, not in Flying Saucer, as far as I am aware).

JskinJskin

 

Hi,

 

Just for information.  I managed to achieve what I wanted using the following:

 

<messaging:attachment renderAs="pdf"  filename="Exam results notification">
<html>
<head><style type="text/css" media="print">
body {color:#666666; font-family:"Arial Unicode MS"; font-size:11pt; font-style:normal;}

@page{
    @bottom-left {                 
    content: element(footer);     
    }
    @top-right {
    content: "Page " counter(page) " of " counter(pages);
    font-family:"Arial Unicode MS";
    font-size:11pt;
    }
    @top-left-corner {
    content: element(header);
    }
    size: A4 portrait;
    margin-top:5cm;
    margin-left:2.54cm;
    margin-right:2.54cm;
    margin-bottom:5cm; 
}

table {
    -fs-table-paginate: paginate;
    }
 

div.footer {
   display: block;
   padding: 10px;                      
   position: running(footer);
   line-height: 10px;
   z-index: 3;
   color: #A9A9A9;
   font-family:"Arial Unicode MS";
   font-size:7.5pt;
              
}

div.header {
   display: block;                     
   position: running(header);
               
}
 
</style>
</head>

<div class="header" >
    <table table-layout="fixed">
    <img src="{!URLFOR($Resource.Document_Logo)}" width="21cm" height="28.7"/>
    </table>
</div>

<div class="footer" >
  <table width="15.92cm" style="left: 2.54cm; top: 27.1cm; line-height: 10pt;" align="left" valign="top" table-layout="fixed">
<tr valign="top">
<td>
address
</td>
</tr>
</table>
</div>

<body>

<table cellpadding="3" cellspacing="0" styleclass="table" width="15cm" border="0.1" style="left: 2.54cm; text-align:center; font-size:11pt;">
        <THEAD>
            <tr>
                <th style="border:1px solid #000000;border-right:0;">Number</th>
                <th style="border:1px solid #000000;border-right:0;">姓名</th>
                <th style="border:1px solid #000000;border-right:0;">單位</th>
                <th style="border:1px solid #000000;border-right:0;">英文姓名</th>
                <th style="border:1px solid #000000;">Pass/Fail</th>
            </tr>
        </THEAD>
            <apex:repeat value="{!relatedTo.Enrollments__r}" var="cx">
        <TBODY>
            <tr>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.name}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.LastNameLocal}{!cx.delegate_name__r.FirstNameLocal}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.department}</td>
                <td style="border:1px solid #000000;border-top:0;border-right:0;">{!cx.delegate_name__r.LastName}{!cx.delegate_name__r.FirstName}</td>
                <td style="border:1px solid #000000;border-top:0;">{!IF(OR(CONTAINS(cx.Exam_results__c,'Fail'),CONTAINS(cx.Exam_results__c,'fail')),'F','P')}</td>
            </tr>
        </TBODY>
        </apex:repeat>
</table>
</body>
</html>
</messaging:attachment>

 

  • I changed the datatable to the code above to produce a table with a single line border around the full table and cells. 
  • Using the  -fs-table-paginate: paginate I got the table with the column headings on each page. 
  • Using the margins on the @page I managed to limit the amount of data shown on each page.
  • And finally using content: element(footer) and content: element(header) I suceeding in showing the correct logo and footer on each page.   

Took a bit longer than I hoped but will be able to reuse this again in future!.

 

 

 

This was selected as the best answer
Camila HeitzCamila Heitz
Hello,

I have my rendered PDF with my header and footer showing, but I can't seem to get my pagination right, my footer gets on top of my content so it doesn't show.
Any ideas on what I can do?
Here's my code:

<apex:page controller="cnReportHoras" showHeader="false" standardStylesheets="false" renderAs="pdf">
   
    <apex:stylesheet value="{!URLFOR($Resource.Estatico, 'css/Style.css')}"/>
     <head>
    
    <link href="https://fonts.googleapis.com/css?family=Comfortaa:300,400,700" rel="stylesheet" type="text/css" />
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,400,300" rel="stylesheet" type="text/css" />
   
     <style>
     @font-face {
  font-family: 'Comfortaa';
  font-style: normal;
  font-weight: 300;
  src: local('Comfortaa Light'), local('Comfortaa-Light'), url(https://themes.googleusercontent.com/static/fonts/comfortaa/v5/r_tUZNl0G8xCoOmp_JkSCnhCUOGz7vYGh680lGh-uXM.woff) format('woff');
}

    table {
    -fs-table-paginate: paginate;
    }
   
    table tr{
    page-break-inside:avoid;
}

#footer_container {
bottom:0;
left:0;
position:fixed;
width:100%;
}
        
#footer {
margin:0 auto;
}

   
#header-cont {
    width:100%;
    position:fixed;
    top:0px;
}

#header {
   
 
margin:0px auto;
}

@page{
    @bottom-left {                
    content: element(footer);    
    }
    @top-right {
    content: "Page " counter(page) " of " counter(pages);
   
    }
    @top-left-corner {
    content: element(header);
    }
   
    margin-top:2cm;
    margin-left:1.54cm;
    margin-right:1.54cm;
    margin-bottom:2cm;
}

div.footer {
display: block;
padding: 5px;
position: running(footer);
}

.pagenumber:before {
content: counter(page);
}

.pagecount:before {
content: counter(pages);
}
     </style>
     </head>
     
     <div id="header-cont">
    <div id="header">
    <img src="{!URLFOR($Resource.Estatico, 'img/s4gheader.png')}" width="100%"/>
    </div>
    </div>
    <div class="clear" style="height:30px;" />
    
   
    
   <body style="margin-top:200px; margin-bottom:60px; font-family: 'Comfortaa'">
  
    <table width="100%" class="tablaGral" >
        <tr>
            <td width="70%">
                <img src="{!URLFOR($Resource.Estatico, 'img/s4g-status.png')}" width="100%" />
             </td>
            
             <td width="30%">
            
               <table class="tableC">
                  <tr>
                       <td>HORAS CONTRATADAS:  </td>
                       <td>{!proyectos[0].horasEstimadas} hrs.</td>
                  </tr>
                  <tr>
                       <td style="vertical-align:middle;">CONSUMO: </td>
                       <td>
                       <apex:image id="activo" value="{!URLFOR($Resource.Estatico, 'img/render1.png')}" width="60" rendered="{!if(proyectos[0].percConsumido<100,true,false)}" />
                       <apex:image id="agotado" value="{!URLFOR($Resource.Estatico, 'img/render2.png')}" width="60" rendered="{!if(proyectos[0].percConsumido>=100,true,false)}" />                      
                      </td>
                  </tr>
                  <tr>
                       <td>TODAVIA QUEDAN: </td>
                       <td>{!proyectos[0].horasRestantes} hrs.</td>
                  </tr>
               </table>
              
             </td>
         </tr>
        
         <tr>
             <td width="20%">
                 <table width="85%">
                     <tr>
                         <th>Cliente </th>
                         <th>Fecha inicio</th>
                         <th>Fecha cierre</th>
                     </tr>
                     <tr>
                     <td>{!proyectos[0].cliente}</td>
                     <td style="color:red;">
                         <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
                            <apex:param value="{!proyectos[0].comienzoPlanificado}" />
                         </apex:outputText>
                     </td>
                     <td style="color:red;">
                         <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
                            <apex:param value="{!proyectos[0].finPlanificado}" />
                         </apex:outputText>
                     </td>
                     </tr>
                 </table>
             </td>
             <td width="80%">
             </td>
         </tr>
        
        
     </table>
     
  
    <div class="clear" style="height:50px;"/>
    <div class="panel panel-vercasos" style="border: 1px solid; ">
  
 
       
         <apex:pageBlock title="Peticiones">
        <apex:pageBlockTable value="{!peticiones}" var="peticion" id="tablaPeticiones" styleClass="table" cellspacing="10" rowClasses="odd,even">
                <apex:column >
                        <apex:facet name="header">Petición</apex:facet>
                        <apex:outputField value="{!peticion.Id_Peticion__c}"/>
                </apex:column>
                <apex:column >
                        <apex:facet name="header">Asunto</apex:facet>
                        <apex:outputField value="{!peticion.subject}"/>
                </apex:column>
                <apex:column >
                        <apex:facet name="header">Horas</apex:facet>
                        <center><apex:outputField value="{!peticion.Horas_estimadas_peticion__c}" /></center>
                </apex:column>
                <apex:column >
                        <apex:facet name="header"><center>Estado</center></apex:facet>
                        <apex:outputField value="{!peticion.Estado_Peticion__c}" />
                </apex:column>
                <apex:column >
                        <apex:facet name="header">Fecha Petición</apex:facet>
                        <center><apex:outputField value="{!peticion.Fecha_Estimada_Peticion__c}" /></center>
                </apex:column>
        </apex:pageBlockTable>
        </apex:pageBlock>
   
    <div class="clear" style="height:20px;" />
   
  
    </div>
   </body>
  
  
   <div id="footer_container">
    <div id="footer">
        <img src="{!URLFOR($Resource.Estatico, 'img/s4gfooter.png')}" width="100%" height="100%"  />
    </div>
    </div>

  
    
</apex:page>



THANK YOU!
VIJAY SINGHVIJAY SINGH
its really work @Jskin 

thanks 
 
Alexis KasperaviciusAlexis Kasperavicius
Thanks very much @Jskin for posting the code. It's enough to show how it works - and it does work! Beautiful!