No support for multi-page unbreakableBlocks
I saw the comment in pageElementWriter.js line 95: // no support for multi-page unbreakableBlocks Is there a reason why this is not supported? Any hints how we could fix this?
When I have a table with a lot of content in one or more rows and the dontBreakRows attribute is set to true; the rows will not get rendered at all. Example:
var dd = {
content: [
{ text: 'Table with a row that is higher than a single page' },
{ table: {
widths: ['*'],
dontBreakRows: true,
body: [
[{ stack:
[
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
{ text: 'Text'},
]
}]
]
}
}]
}
Is this is planned to be fixed ?
There are no immediate plans to fix it.
Also: It's hard to know when to break a block when the user of the API specified the block as "unbreakable".
On Sun, Jun 21, 2015 at 1:05 PM, Elyahou [email protected] wrote:
Is this is planned to be fixed ?
— Reply to this email directly or view it on GitHub https://github.com/bpampuch/pdfmake/issues/207#issuecomment-113885321.
I have a large table that doesn't fit on one page and as a whole but has reasonable sections where it could be broken. I'd like to set the whole table so it doesn't break, but then set a 'breakHint' or something so the system knows where it is allowed to break.
Same here for dynamic stack content. I need a way to keep small dynamic stack content together but also render content that does not fit to one page.
// playground requires you to assign document definition to a variable called dd
var dd = {
content: [{
unbreakable: true,
stack: [
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'},
{text: 'test'}
]
}]
}
Would an acceptable solution for this be to ignore unbreakable if the content is larger than one page?
I would still prefer a way to hint where the break should end up, but a solution that at the least spent drop the content, would be minimally acceptable.
I'm going to take a stab at fixing this. @jthoenes why do you say this:
Also: It's hard to know when to break a block when the user of the API specified the block as "unbreakable".
It looks like the hight of the block is set in PageElementWriter::commitUnbreakableBlock on line 104
Could we not just add something like this:
if (fragment.height > this.context().getCurrentPage().pageSize) {
// Content is too big, make content unbreakable then render as normal
return super.addFragment(fragment);
}
Is the issue that the block height is available only because it's is already rendered at this point? I'd love to get a conversation going about this issue. Any possible solutions or suggestion much appreciated (particularly from @liborm85 ).
Any preliminary solution like the one you just suggested would be very much appreciated. I would consider it a bug fix while working on more advanced features for page-break corner cases like the hinting suggested further up.
Things not ending up on the pdf at all because they couldn't be placed in the requested pretty way is a bug equivalent to the printer "out of magenta" way of dealing with printouts.
I suggest that an unbreakable that has multiple pages, simply start the unbreakable in a new page and then break where it should break, like not being an unbreakable.
Something like "break before if don't fits in the remaining space".
@jwerre Did you get around to trying this workaround? I just came across the issue and was planning to fork and patch with something similar but would be great if you could share some code / elaborate on any difficulty you ran into.
@ramijarrar I didn't get around to fixing this. It's been a while but I believe the issue is that you can't get the height of the block until it has been rendered on the page. I'm still interested in a fix for this so I'd be eager to know what you come up with.
I have also come across this issue - it's quite a big blocker for my project. Is there a way of 'catching' the issue (i.e. identifying when an unbreakable block is more than a page long) and then re-rendering without unbreakable:true and just with a pagebreak:before?
I posted a $500 bounty at BountySource if anyone wants to take a stab at this.
Hi @jwerre i want to take a look at this, but could be the aproach mentioned by @paprikati and @Llorx an accepted solution ??
I mean if the unbreakable block is larger than page size, then start it in a new page and break it where needs ?
For me the desired behaviour would be - if it hits a block that is too big:
- add page break before
- respect any unbreakable:true flags on child components while continuing to render
As it stands now if a block is marked as unbreakable and the block is longer than a page then the entire block is not rendered.
I think the best solution would be to simply ignore the unbreakable flag if the block is longer than the page.
I get why you would add a before break to try and fit it on the next page, but if it doesn't fit on the next page then you end up with unnecessary white space. If the block doesn't fit on the next page either then it should go back to the position before the page break and render from there.
As it stands now if a block is marked as
unbreakableand the block is longer than a page then the entire block is not rendered.I think the best solution would be to simply ignore the
unbreakableflag if the block is longer than the page.I get why you would add a before break to try and fit it on the next page, but if it doesn't fit on the next page then you end up with unnecessary white space. If the block doesn't fit on the next page either then it should go back to the position before the page break and render from there.
Maybe that can be an option. "Render on next page or ignore unbreakable".
I guess the easy way is to ignore it. We could start with that.
I would expect that it would incrementally push the unbreakable property to the next largest block until the blocks can fit on a page.
block1 unbreakable
block1.2
block1.3
block1.3.1
block1.4
if block1 won't fit, becomes
block1
block1.2 unbreakable
block1.3 unbreakable
block1.3.1
block1.4 unbreakable
if block 1.3 won't fit, becomes
block1
block1.2 unbreakable
block1.3
block1.3.1 unbreakable
block1.4 unbreakable
I would also expect that pagebefore type behavior would be triggered by some percentage of the page available... If 50% (configurable) of the page already has content then do a pagebefore if not then don't.
I guess the easy way is to ignore it. We could start with that.
@willy2dg, I agree, let's start with a simple and see where we end up. But I do agree, it would be nice to add a pagebreak before a block if the block can fit on the next page else ignore.
@s7726 I think you're overcomplicating it a bit. I also think an arbitrary 50% (or any percent for that matter) doesn't make much sense when the following block could be any length.
@jwerre might be overcomplicating it for the initial cut, but it's always nice to have an idea where the end goal might be.
I agree percentage might not make the most sense, maybe a measurement of some kind (in, cm, etc.). It would be nice to have some control over the allowed amount of blank page at the bottom, if the block is going to be forced to break. i.e. I might not want to start on a fresh page with the whole big block if there is only one line of text on the page it's breaking from.
@jwerre - for me the priority is preserving unbreakable blocks within the larger block - where something like a table row should by 'default' be considered unbreakable. That gives the user the option to sub-divide their larger blocks into smaller ones if they need the kind of control that @s7726 would describe.
@paprikati That would be better for sure. Sound doable @willy2dg?
@jwerre I will look into the code more in deep and give you some feedback as soon as possible.
I made a quick fix; still working on it
@denim2x, for the sake of time, can you explain how you fixed it and what you've done?
the fix is at an early stage - the table gets rendered all right, but only on the page where it starts
I've made some progess

Next I'll ensure that paragraphs exceeding page height shall be divided into smaller fragments
For this to work it'd be better if pdfmake was based on coroutines/message queues, at least the modules TableProcessor and PageElementWriter (which contains beginUnbreakableBlock()); that means a lot more working going into it, so it'd be much appreciated if the funding for this issue was increased