Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go to the next page with a specific condition (conditional page break) #283

Open
mehrdadTemp opened this issue Sep 12, 2022 · 7 comments
Open
Labels

Comments

@mehrdadTemp
Copy link

mehrdadTemp commented Sep 12, 2022

HI

how to go to the next page (go to next docx page and keep going) with a specific condition like

+++IF condition +++
+++= page_break +++
+++END-IF+++

In python can use this
//code
from docxtpl import DocxTemplate, R, InlineImage
page_break = R('\f')
//docx template
{% if condition %}
{{r page_break }}
{% endif %}

and how use index in FOR

and when try merge two docx file catch this error
"For source /word/document.xml, cannot find part word/media/template_document.xml_img1.jpg from rel img1=media/template_document.xml_img1"
i can not get this error with docxtpl before

@jjhbw
Copy link
Collaborator

jjhbw commented Oct 6, 2022

Haven't tried this before, but what about adding a literal page break in between an IF-END-IF in the template? If not, you can look into using literal XML for this. I don't know the required XML magic, though. You may be able to find that here http://officeopenxml.com/anatomyofOOXML.php or here https://stackoverflow.com/questions/2795315/create-page-break-using-openxml

Would appreciate it if you could post in this thread what ended up working for you.

@jjhbw jjhbw added the question label Oct 6, 2022
@SuchiraD
Copy link
Contributor

I have faced a similar situation and following is what I have used.
In JS code,

createReport({
            template,
            data: {
                ...data,
                pageBreak: '||<w:br w:type="page" />||',
            },
            cmdDelimiter: ['{{', '}}'],
        });

In template

{{ IF condition }}
{{pageBreak}}
{{ END-IF }}

@jjhbw jjhbw pinned this issue Feb 20, 2023
@jjhbw jjhbw changed the title go to the next page with a specific condition go to the next page with a specific condition (conditional page break) Apr 4, 2023
@davidjb
Copy link
Contributor

davidjb commented Aug 16, 2023

In a similar vein, I solved this with:

const report = await createReport({
  ...
  additionalJsContext: {
      pagebreak: (show) => (show || typeof show === 'undefined') ? '||<w:br w:type="page"/>||' : '',
  }
})

which slims down the syntax a bit whilst allowing any given conditional or falsy value to prevent the break from showing, such as:

{{ pagebreak($idx < $component.issues.length-1) }}
{{ pagebreak($idx < 5) }}
{{ pagebreak($name === 'Alice') }}
{{ pagebreak($data) }}

pagebreak() can also be called without an argument to always output a break (or used within other contexts such as IF).

@jjhbw
Copy link
Collaborator

jjhbw commented Aug 16, 2023

Thanks for this solution @davidjb !! 🥳

@JPBM135
Copy link

JPBM135 commented Sep 9, 2023

I encountered a problem with this method, since the <w:br w:type="page"/> comes wrapped inside an

<w:t xml:space="preserve">
    <w:br w:type="page" />
</w:t>

So I'd actually had to replace the text manually, here is the snippet if anyone wants it:

export function sanitizeDocumentXml(bin: Uint8Array) {
  try {
    writeFileSync('/tmp/template.docx', bin);
    execSync('unzip -o /tmp/template.docx -d /tmp/template');

    const documentXml = readFileSync('/tmp/template/word/document.xml', 'utf8');

    const sanitizedDocumentXml = documentXml.replaceAll(
      '<w:t xml:space="preserve"><w:br w:type="page" /></w:t>',
      '<w:br w:type="page" />',
    );

    writeFileSync('/tmp/template/word/document.xml', sanitizedDocumentXml);
    execSync('cd /tmp/template && zip -r /tmp/template.docx ./*');

    return readFileSync('/tmp/template.docx');
  } catch (error) {
    console.log('[sanitizeDocumentXml]: error', error);
    return bin;
  }
}

I believe this is compatible with most operation systems, but I tested in linux

@Vitomir2
Copy link

I have faced a similar situation and following is what I have used. In JS code,

createReport({
            template,
            data: {
                ...data,
                pageBreak: '||<w:br w:type="page" />||',
            },
            cmdDelimiter: ['{{', '}}'],
        });

In template

{{ IF condition }}
{{pageBreak}}
{{ END-IF }}

Hey @SuchiraD, for some reason this does not break my pages. Here is my template:

*FOR chartData IN chartsData*
*pageBreak*

*$chartData.question*

*IMAGE chart($chartData.imageSrc)*

*IF $chartData.table*
*IMAGE table($chartData.table)*
*END-IF*

*END-FOR chartData*

then, the code:

const buffer = await createReport({
        cmdDelimiter: ['*', '*'],
        template,
        additionalJsContext: {
            pageBreak: '||<w:br w:type="page" />||,
            chartsData,
            chart: (imageSrc) => {
                ...
            },
            table: (table) => {
                ...
            }
        }
    })

and here is the result:
image

@SuchiraD
Copy link
Contributor

then, the code:

const buffer = await createReport({
        cmdDelimiter: ['*', '*'],
        template,
        additionalJsContext: {
            pageBreak: '||<w:br w:type="page" />||,
            chartsData,
            chart: (imageSrc) => {
                ...
            },
            table: (table) => {
                ...
            }
        }
    })

and here is the result: image

@Vitomir2 , Sorry for very late late reply. Somehow I have missed this comment

I am not very clear on the second part of your comment. Were you able to do the pageBreak by adding it in additionalJsContext?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants