11

For a project im making offer and invoice pdf's on the fly using pdfmake in javascript. The problem im facing is having text blocks going off the page in the middle. What i want is to check if a certain block of text or a table is going to be split between pages and if so add a pagebreak before the block to make sure the text or table will be entirely on one page.

My pdf docDefinition is build like this:

return {
                content: [
                    getOfferLogo(), //Get the logo or empty string
                    getHeading(), //get the customer and business data (adress etc)
                    //the above is always the same
                    getText(), //get the textblock, created by user and always different
                    getSpecifics(), //get a table of payment specifications
                    getSignature() //get last textblock contaning signature fields etc, always the same
                ],
                styles: {
                    subheader: {
                        fontSize: 15,
                        bold: true,
                        alignment: 'center'
                    }
                },
                defaultStyle: {
                    columnGap: 20,
                    fontSize: 12
                }
            };

So in short how can i check if text will be going off the page before creating the pdf and add pagebreaks accordingly?

Thanks in advance.

André Kool
  • 4,880
  • 12
  • 34
  • 44

4 Answers4

37

The pageBreakBefore function gives a lot of flexibility in determining whether the page break is required or not. However, I've found one more solution which is more straightforward and less documented but does all the magic automatically. It's a unbreakable: true attribute that came in 0.1.32 release. Also, it mentioned in the following thread https://github.com/bpampuch/pdfmake/issues/1228#issuecomment-354411288

How it works? For instance, you want to make a header and some text below it to be unbreakable. In order to do it, you have to wrap the header and the content in a stack and apply the unbreakable: true on it.

{
    stack: [
        // header
        {
            text: 'Lorem ipsum dolor sit amet',
            bold: true,
            fontSize: 13
        },
        // content
        {
            text: 'Nulla iaculis magna vitae luctus euismod. Sed arcu risus, mattis non molestie et, condimentum sit amet justo. Quisque vitae neque magna. Etiam in tellus vitae arcu volutpat bibendum. In ullamcorper ante tortor, a viverra libero cursus eu. Phasellus quis massa nec lorem feugiat ultricies. Aliquam erat volutpat. Nullam a purus tempus, feugiat elit vel, tincidunt tortor.'
        }
    ],
    unbreakable: true // that's the magic :)
}
Vitalii Bratok
  • 701
  • 1
  • 7
  • 9
  • I have moved on to different projects in the time after I asked this question years ago so unfortunatly I won't be able to validate this. But looking at this answer and the linked info you provided it sounds like a very good solution. – André Kool Aug 29 '18 at 09:47
  • 4
    I can confirm that this solution is working as advertised. – MazBeye Oct 29 '18 at 06:34
  • Works like a charm. I'm using pdfmake v0.1.58 – svaj Aug 25 '19 at 04:56
  • If you are using typescript and using the PDFmake types, you might need to set the type of the object to `ContentStack` – Ramtin Mar 01 '21 at 02:19
  • magic worked! ''unbreakable: true'' made my day, thanks! – neekheel Sep 28 '22 at 05:28
  • 1
    pay attention to the fact that if the unbreakable stack is longer than the page it will simply disappear... :\ – Elazar Zadiki Jan 18 '23 at 13:10
  • This is absolute gold and should be the accepted answer as it addresses the question. – Dan Hobbs Apr 04 '23 at 10:49
15

Found the solution :)

In the DocDefinition you can add a function for pageBreakBefore like this:

content: [{
    text: getOfferClosingParagraph(),
    id: 'closingParagraph'
  }, {
    text: getSignature(),
    id: 'signature'
  }],
  pageBreakBefore: function(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
    //check if signature part is completely on the last page, add pagebreak if not
    if (currentNode.id === 'signature' && (currentNode.pageNumbers.length != 1 || currentNode.pageNumbers[0] != currentNode.pages)) {
      return true;
    }
    //check if last paragraph is entirely on a single page, add pagebreak if not
    else if (currentNode.id === 'closingParagraph' && currentNode.pageNumbers.length != 1) {
      return true;
    }
    return false;
  },

For more info about this function and the information provided take a look at this

André Kool
  • 4,880
  • 12
  • 34
  • 44
1

Simple example with texts:

var dd = {
    content: [
        'First paragraph',
        
        // page break before text
        {text: 'Text on the next page', pageBreak: 'before'},
        
        'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines',
        
        // page break after text
        {text: 'Text is lastest on the page', pageBreak: 'after'},
        
        'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
    ]
}
Sushil
  • 670
  • 7
  • 14
-1
pageBreakBefore: (currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) => {
    if (currentNode.id === 'yournodeid') {
        if(previousNodesOnPage[0].startPosition.pageNumber != followingNodesOnPage[0].pageNumbers) {
            return true;
        }
    }
    return false;
}
Conny Olsson
  • 1,567
  • 2
  • 11
  • 19