6

I have a pageblocktable that is being rendered as a pdf. The PDF is set as A4 landscape with small margins and page numbering in a style sheet. The problem is that rows in the pageblocktable span the page break, any text above and below is split on the line, making it difficult to read that line. The lines heights are content-dependent, so I cannot add some sort of padding at a set point to force the page breaks where I want them.

The problem as I interpret it is that pageblocktables are contiguous, if you display one on a normally rendered page it will be one big block without breaks. When you say to render as PDF it simply takes the visuals, puts them into a graphic format, then slices it into pieces that fit the page margins.

Is there anything I can do in the style sheet or the page code to get the engine to be aware of the page break?

my somewhat redacted page code:

<apex:page controller="MyCustomController" title="My List" renderAs="pdf"> <apex:stylesheet value="{!URLFOR($Resource.pdfresources)}"/> <apex:form > <apex:pageBlock title="My List" mode="Edit" > <apex:pageBlockTable value="{!DataList}" var="data" width="100%" headerClass="tableHeader" cellPadding="2px"> columns here

Here's a screenshot, you can clearly see the bleed-over. enter image description here

  • Can you post a screenshot? – Sergej Utko Apr 9 '13 at 13:50
  • @mast0r, done. It's only partial, I cannot show the whole row, but the coloring shows how it bleeds over the page break. – GdD Apr 9 '13 at 14:05
2

You can set page breaks via CSS, though you may have to change your page's structure to accomplish this. There is a good example on Developerforce that demonstrates this. It works as follows:

  1. A two-dimensional array
  2. Using <apex:repeat> or a similar construct
  3. Having your controller populate the 2-d array

In your controller:

  1. Execute the SOQL to generate your list of results
  2. Populate the 2-D array as follows
    1. Each outer element represents a page worth of results
    2. Each inner array represents the rows to display

In your VF page:

  1. An outer loop to generate each page
  2. An inner loop to generate each row
  3. CSS to provide page-break-after:always; at the end of each page

The number of elements that you can fit on a page will vary and require some experimentation to get right. Also note that working in Development Mode breaks the CSS as I found out the hard way.

  • Thanks @MikeChale, that's really good information. Whey you say an outer element represents a page worth of results how do I know what a page of results is? The row height is dynamic depending on content, so the number of rows in a page will differ every time the page is generated. – GdD Apr 9 '13 at 14:23
  • If the row height is always variable then it may be impossible. Can you set it to a fixed height? Do you know a maximum size? – Mike Chale Apr 9 '13 at 14:27
  • I find the number of elements per page by trial and error; I don't know of any other method. – Mike Chale Apr 9 '13 at 14:28
  • setting a fixed height is a no-go unfortunately. The difference between maximum and minimum is large, and most of the lines are closer to the minimum, so there would be too much wasted space and make it look unreadable. Is there a way I could calculate row height on the fly, and insert a page break if the next line is going to span the break? – GdD Apr 9 '13 at 14:39
  • Probably, with some fancy JavaScript/jQuery if you were doing HTML. I don't know if that is possible when rendering a PDF. jQuery has a .height() method api.jquery.com/height – Mike Chale Apr 9 '13 at 14:42
2

If you look at Best Practices for Rendering PDFs you'll discover that <apex:pageBlock> and <apex:pageBlockTable> are both listed as Components That Are Unsafe to Use in a PDF. You'll want to convert your page to use html tables to display your data. You can set padding using the html table attributes and you can also force page breaks using CSS. A good reference for all of the table settings can be found at http://www.w3.org/TR/1999/REC-html401-19991224/struct/tables.html. From the table of contents there, you'll also find links to the related CSS.

Edited to add:

Here's an additional link that should help you with your pagination issues if you want to create a custom controller to do the pagination work for you instead of relying entirely on CSS: Creating Professional PDF Documents with CSS and Visualforce. The method described in the article uses the controller to layout the content before it's sent to the page, effectively doing the pagination in the controller rather than creating page breaks using what I'll refer to as "smart CSS with HTML".

  • I was afraid that would be the answer. I may just have to live with the line bleed until I have a chance to re-develop. Doh! – GdD Apr 9 '13 at 14:24
  • See the article I've add the link to in my reply above. You may find it helpful to you in resolving your issues. :) – crmprogdev Apr 9 '13 at 18:41
  • Oops! Sorry @Mike Chale, I didn't realize you'd provided the same link! – crmprogdev Apr 10 '13 at 12:59
1

Is it about the text in one row being split across pages or the fact that only one next row spills over to next page?

The first one might be remedied by experimenting with

tr {page-break-inside:avoid; page-break-after:auto}

The later - try using the CSS "orphans" setting for print media (I assume you already use some @page rules to display the footers).

<style tyle="text/css">
<!--
@page{orphans:4; widows:2;}
-->
</style>

I found http://www.tutorialspoint.com/css/css_paged_media.htm to be quite useful. Also simplify the markup as Mike suggests, use plain <apex:repeat> + html instead of pageBlockTable (manually create the <thead>, <th> and <tr> tags).


"Proper" rendering engines would simply respect the display-table-header rule (which is supposed to repeat table headers after page break and thus make table look nice again). Sadly this doesn't seem to work in Salesforce; http://www.evagoras.com/2011/02/10/printing-table-headers-on-every-page/ is a nice example but it's browser-specific and doesn't work in the engine that's responsible for renderAs="pdf".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.