You are currently offline, serving cached version

Frequently asked questions

Inserting new lines

const doc = new Docxtemplater(zip, {
    linebreaks: true,
    paragraphLoop: true,
});
doc.render(/* data */);

then in your data, if a string contains a newline, it will be translated to a linebreak in the document.

Insert HTML formatted text

It is possible to insert HTML formatted text using the HTML pro module

Generate smaller docx using compression

The size of the docx output can be big, in the case where you generate the zip the following way:

doc.getZip().generate({ type: "nodebuffer" });

This is because the zip will not be compressed in that case. To force the compression (which will slow down the generation for output files larger than 10 MB).

const buf = doc.getZip().generate({
    type: "nodebuffer",
    // compression: DEFLATE adds a compression step.
    // For a 50MB output document, expect 500ms additional CPU time
    compression: "DEFLATE",
});
fs.writeFileSync("output.docx", buf);

Writing if else

To write if/else, see the documentation on sections for if and inverted sections for else.

Using boolean operators (AND, OR) and comparison operators (<, >)

You can also have conditions with comparison operators (< and >), or boolean operators (&& and ||) using angular parser conditions.

Conditional Formatting

With the docxtemplater styling module it is possible to have a table cell be styled depending on a given condition (for example).

Using data filters

You might want to be able to show data a bit differently for each template. For this, you can use the angular parser and the filters functionality.

For example, if a user wants to put something in uppercase, you could write in your template:

{ user.name | uppercase }

See angular parser for comprehensive documentation

Keep placeholders that don't have data

It is possible to define which value to show when a tag resolves to undefined or null (for example when no data is present for that value).

For example, with the following template

Hello {name}, your hobby is {hobby}.
{
    "hobby": "football"
}

The default behavior is to return "undefined" for empty values.

Hello undefined, your hobby is football.

You can customize this to either return another string, or return the name of the tag itself, so that it will show:

Hello {name}, your hobby is football.

It is possible to customize the value that will be shown for {name} by using the nullGetter option. In the following case, it will return "{name}", hence it will keep the placeholder {name} if the value does not exist.

function nullGetter(part) {
    if (part.raw) {
        return "{" + part.raw + "}";
    }
    if (!part.module && part.value) {
        return "{" + part.value + "}";
    }
    return "";
}
const doc = new Docxtemplater(zip, {
    nullGetter,
    linebreaks: true,
    paragraphLoop: true,
});
doc.render(/* data */);

Highlight placeholders that don't have data

If you have access to the HTML module, it is possible to highlight fields that have no data.

The following template, when having no "age" property :

Hello {name}, age {age}

Will render :

Hello John, age {age}

See this documentation part to see how to make this work.

Performance

Docxtemplater is quite fast, for a pretty complex 50 page document, it can generate 250 output of those documents in 44 seconds, which is about 180ms per document.

There also is an interesting blog article on my personal blog that explains how I optimized loops in docxtemplater back in 2016.

Support for IE9 and lower

docxtemplater should work on almost all browsers: IE7+, Safari, Chrome, Opera, Firefox.

The only 'problem' is to load the binary file into the browser. This is not in docxtemplater's scope, but here is the recommended code to load the zip from the browser.

The following code should load the binary content on all browsers:

PizZipUtils.getBinaryContent(
    "path/to/content.zip",
    function (err, data) {
        if (err) {
            throw err; // or handle err
        }

        const zip = new PizZip(data);
        const doc = new Docxtemplater(zip);
        doc.render(/* data */);
    }
);

Get list of placeholders

To be able to construct a form dynamically or to validate the document beforehand, it can be useful to get access to all placeholders defined in a given template. Before rendering a document, docxtemplater parses the Word document into a compiled form. In this compiled form, the document is stored in an AST which contains all the necessary information to get the list of the variables and list them in a JSON object.

With the simple inspection module, it is possible to get this compiled form and show the list of tags. suite:

const InspectModule = require("docxtemplater/js/inspect-module.js");
const iModule = InspectModule();
const doc = new Docxtemplater(zip, {
    modules: [iModule],
    linebreaks: true,
    paragraphLoop: true,
});
doc.render(/* data */);
const tags = iModule.getAllTags();
console.log(tags);
// After getting the tags, you can render the document like this:
// doc.render(data);

With the following template:

{company}

{#users}
{name}
{age}
{/users}

It will log this object:

{
    "company": {},
    "users": {
        "name": {},
        "age": {}
    }
}

To know which modules are used for each tag (image-module/raw-xml-module/loop-module/style-module), it is possible to instead use the getStructuredTags API :

const InspectModule = require("docxtemplater/js/inspect-module.js");
const iModule = InspectModule();
const doc = new Docxtemplater(zip, {
    modules: [iModule],
    linebreaks: true,
    paragraphLoop: true,
});
const tags = iModule.getStructuredTags();
console.log(tags);
// After getting the tags, you can render the document like this:
doc.render(data);

You can also get the whole compiled document using:

const InspectModule = require("docxtemplater/js/inspect-module.js");
const iModule = InspectModule();
const doc = new Docxtemplater(zip, {
    modules: [iModule],
    linebreaks: true,
    paragraphLoop: true,
});
// for Word documents :
console.log(iModule.fullInspected["word/document.xml"]);
// for Powerpoint presentations :
console.log(iModule.fullInspected["ppt/slides/slide1.xml"]);
// for Excel sheets :
console.log(iModule.fullInspected["xl/worksheets/sheet1.xml"]);
doc.render(/* data */);

Here's the code of the inspect-module, which you can use as an inspiration to retrieve the exact information that you need in the structure that you want.

Note about the angular-expressions feature with the tag {%img | size:20:20} this will output to you : img | size:20:20

You can extract only the Identifiers from the angular-expressions using this function (this needs docxtemplater 3.37.2) :

const expressionParser = require("docxtemplater/expressions.js");
const tag = "img | size:200:300";
const identifiers = expressionParser(tag).getIdentifiers();
console.log(identifiers);
// identifiers will be ["img"]
// For the tag { firstName + lastName }, it will return ["firstName", "lastName"]

Convert to PDF

It is not possible to convert docx to PDF with docxtemplater, because docxtemplater is a templating engine and doesn't know how to render a given document. There are many tools to do this conversion.

The first one is to use libreoffice headless, which permits you to generate a PDF from a docx document:

You just have to run:

libreoffice --headless --convert-to pdf --outdir . input.docx

This will convert the input.docx file into input.pdf file.

The rendering is not 100% perfect, since it uses libreoffice and not microsoft word. If you just want to render some preview of a docx, I think this is a possible choice. You can do it from within your application by executing a process, it is not the most beautiful solution but it works.

If you want something that does the rendering better, I think you should use some specialized software.

The ones I do recommend would be (most recommended on top, I have no partnership with any of those recommendations) :

  1. ConvertAPI , commercial, API

  2. Apryse, commercial, can be self hosted

  3. Aspose Commercial, Cloud

  4. cm2pdf, Commercial, self-hosted, command line

Pptx support

Docxtemplater handles pptx files without any special configuration (since version 3.0.4).

It does so by looking at the content of the "[Content_Types].xml" file and by looking at some docx/pptx specific content types.

My document is corrupted, what should I do ?

If you are inserting multiple images inside a loop, it is possible that word cannot handle the docPr attributes correctly. You can try to add the following code before instantiating the Docxtemplater instance.

const fixDocPrCorruptionModule = {
    set(options) {
        if (options.Lexer) {
            this.Lexer = options.Lexer;
        }
        if (options.zip) {
            this.zip = options.zip;
        }
    },
    on(event) {
        if (event === "attached") {
            this.attached = false;
        }
        if (event !== "syncing-zip") {
            return;
        }
        const zip = this.zip;
        const Lexer = this.Lexer;
        let prId = 1;
        function setSingleAttribute(partValue, attr, attrValue) {
            const regex = new RegExp(
                `(<.* ${attr}=")([^"]+)(".*)$`
            );
            if (regex.test(partValue)) {
                return partValue.replace(
                    regex,
                    `$1${attrValue}$3`
                );
            }
            let end = partValue.lastIndexOf("/>");
            if (end === -1) {
                end = partValue.lastIndexOf(">");
            }
            return (
                partValue.substr(0, end) +
                ` ${attr}="${attrValue}"` +
                partValue.substr(end)
            );
        }
        zip.file(/\.xml$/).forEach(function (f) {
            let text = f.asText();
            const xmllexed = Lexer.xmlparse(text, {
                text: [],
                other: ["wp:docPr"],
            });
            if (xmllexed.length > 1) {
                text = xmllexed.reduce(function (
                    fullText,
                    part
                ) {
                    if (
                        part.tag === "wp:docPr" &&
                        ["start", "selfclosing"].indexOf(
                            part.position
                        ) !== -1
                    ) {
                        return (
                            fullText +
                            setSingleAttribute(
                                part.value,
                                "id",
                                prId++
                            )
                        );
                    }
                    return fullText + part.value;
                }, "");
            }
            zip.file(f.name, text);
        });
    },
};
const doc = new Docxtemplater(zip, {
    modules: [fixDocPrCorruptionModule],
    linebreaks: true,
    paragraphLoop: true,
});
doc.render(/* data */);

Attaching modules for extra functionality

If you have created or have access to docxtemplater PRO modules, you can attach them with the following code:

const doc = new Docxtemplater(zip, {
    modules: [
        /* ...*/
    ],
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(data);

Ternaries are not working well with angular-parser

There is a common issue which is to use ternary on scopes that are not the current scope, which makes the ternary appear as if it always showed the second option.

For example, with following data:

doc.render({
    user: {
        gender: "F",
        name: "Mary",
        hobbies: [
            {
                name: "play football",
            },
            {
                name: "read books",
            },
        ],
    },
});

And by using the following template:

{#user}
{name} is a kind person.

{#hobbies}
- {gender == 'F' : 'She' : 'He'} likes to {name}
{/hobbies}
{/}

This will print:

Mary is a kind person.

- He likes to play football
- He likes to read books

Note that the pronoun "He" is used instead of "She".

The reason for this behavior is that the {gender == 'F' : "She" : "He"} expression is evaluating in the scope of hobby, where gender does not even exist. Since the condtion gender == 'F' is false (since gender is undefined), the return value is "He". However, in the scope of the hobby, we do not know the gender so the return value should be null.

We can instead write a custom filter that will return "She" if the input is "F", "He" if the input is "M", and null if the input is anything else.

The code would look like this:

const expressionParser = require("docxtemplater/expressions.js");
expressionParser.filters.pronoun = function (input) {
    if (input === "F") {
        return "She";
    }
    if (input === "M") {
        return "He";
    }
    return null;
};

And use the following in your template:

{#user}
{name} is a kind person.

{#hobbies}
- {gender | pronoun} likes to {name}
{/hobbies}
{/}

Multi scope expressions do not work with the angularParser

Since version 3.32.3, this behavior should be fixed if you use the following parser :

const expressionParser = require("docxtemplater/expressions.js");
new Docxtemplater(zip, {
    parser: expressionParser,
    paragraphLoop: true,
    linebreaks: true,
});

Access to XMLHttpRequest at file.docx from origin 'null' has been blocked by CORS policy

This happens if you use the HTML sample script but are not using a webserver.

If your browser window shows a URL starting with file://, then you are not using a webserver, but the filesystem itself.

For security reasons, the browsers don't let you load files from the local file system.

To do this, you have to setup a small web server.

The simplest way of starting a webserver is to run following command:

npx http-server
# if you don't have npx, you can also do:
# npm install -g http-server && http-server .

On your production server, use a more robust webserver such as nginx, or any webserver that you are currently using for static files.

Docxtemplater in a React project

There is an online react demo available on stackblitz.

You can use the following code:

import React from "react";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";

function loadFile(url, callback) {
    PizZipUtils.getBinaryContent(url, callback);
}

export const App = class App extends React.Component {
    render() {
        function generateDocument() {
            loadFile(
                "https://docxtemplater.com/tag-example.docx",
                function (error, content) {
                    if (error) {
                        throw error;
                    }
                    const zip = new PizZip(content);
                    const doc = new Docxtemplater(zip, {
                        paragraphLoop: true,
                        linebreaks: true,
                    });
                    doc.render({
                        first_name: "John",
                        last_name: "Doe",
                        phone: "0652455478",
                        description: "New Website",
                    });
                    const out = doc.getZip().generate({
                        type: "blob",
                        mimeType:
                            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                    }); // Output the document using Data-URI
                    saveAs(out, "output.docx");
                }
            );
        }

        return (
            <div className="p-2">
                <h1>Test docxtemplater</h1>
                <button onClick={generateDocument}>
                    Generate document
                </button>
                <p>
                    Click the button above to generate a document
                    using ReactJS
                </p>
                <p>
                    You can edit the data in your code in this
                    example. In your app, the data would come
                    from your database for example.
                </p>
            </div>
        );
    }
};

Docxtemplater in an angular project

There is an online angular demo available on stackblitz.

If you are using an angular version that supports the import keyword, you can use the following code:

import { Component } from "@angular/core";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";

function loadFile(url, callback) {
    PizZipUtils.getBinaryContent(url, callback);
}

@Component({
    selector: "app-product-list",
    templateUrl: "./product-list.component.html",
    styleUrls: ["./product-list.component.css"],
})
export class ProductListComponent {
    generate() {
        loadFile(
            "https://docxtemplater.com/tag-example.docx",
            function (error: Error | null, content: string) {
                if (error) {
                    throw error;
                }
                const zip = new PizZip(content);
                const doc = new Docxtemplater(zip, {
                    paragraphLoop: true,
                    linebreaks: true,
                });
                doc.render({
                    first_name: "John",
                    last_name: "Doe",
                    phone: "0652455478",
                    description: "New Website",
                });
                const out = doc.getZip().generate({
                    type: "blob",
                    mimeType:
                        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                });
                // Output the document using Data-URI
                saveAs(out, "output.docx");
            }
        );
    }
}

Docxtemplater in a Vuejs project

There is an

There is an online vuejs 3.x demo available on stackblitz. The vuejs 2.x demo is here.

If you are using vuejs version that supports the import keyword, you can use the following code:

import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";

function loadFile(url, callback) {
    PizZipUtils.getBinaryContent(url, callback);
}

export default {
    methods: {
        renderDoc() {
            loadFile(
                "https://docxtemplater.com/tag-example.docx",
                function (error, content) {
                    if (error) {
                        throw error;
                    }
                    const zip = new PizZip(content);
                    const doc = new Docxtemplater(zip, {
                        paragraphLoop: true,
                        linebreaks: true,
                    });
                    doc.render({
                        first_name: "John",
                        last_name: "Doe",
                        phone: "0652455478",
                        description: "New Website",
                    });

                    const out = doc.getZip().generate({
                        type: "blob",
                        mimeType:
                            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                    });
                    // Output the document using Data-URI
                    saveAs(out, "output.docx");
                }
            );
        },
    },

    template: `
    <button @click="renderDoc">
       Render docx template
    </button>
  `,
};

Docxtemplater in a Next.js project

There is an online nextjs demo available on stackblitz.

You can use the following code:

"use client";

import React from "react";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import { saveAs } from "file-saver";
let PizZipUtils = null;
if (typeof window !== "undefined") {
    import("pizzip/utils/index.js").then(function (r) {
        PizZipUtils = r;
    });
}

function loadFile(url, callback) {
    PizZipUtils.getBinaryContent(url, callback);
}

function generateDocument() {
    loadFile(
        "https://docxtemplater.com/input.docx",
        function (error, content) {
            if (error) {
                throw error;
            }
            const zip = new PizZip(content);
            const doc = new Docxtemplater(zip, {
                linebreaks: true,
                paragraphLoop: true,
            });
            // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
            doc.render({
                first_name: "John",
                last_name: "Doe",
                phone: "0652455478",
                description: "New Website",
            });
            const blob = doc.getZip().generate({
                type: "blob",
                mimeType:
                    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            });
            // Output the document using Data-URI
            saveAs(blob, "output.docx");
        }
    );
}

export default function Home() {
    return (
        <main>
            <div>
                <div>
                    <h1> Test Docxtemplater</h1>
                </div>
                <button onClick={generateDocument}>
                    Generate document
                </button>
                <p>
                    Click the button above to generate a document
                    using NextJS
                </p>
                <p>
                    You can edit the data in your code in this
                    example. In your app, the data would come
                    from your database for example.
                </p>
            </div>
        </main>
    );
}

Adding page break from a tag

It is possible, in a rawxmltag, to add a page break. For example this could allow you to conditionally add a page break.

The template will look like this:

{#cond}
{@pageBreak}
{text}
{/}

In your code, use the following :

const doc = new Docxtemplater(zip, {
    paragraphLoop: true,
    linebreaks: true,
});
doc.render({
    cond: true,
    pageBreak: '<w:p><w:r><w:br w:type="page"/></w:r></w:p>',
    text: "Hello world",
});

Getting access to page number / total number of pages height of element or regenerate Table of Contents

Sometimes, you would like to know what are the total number of pages in the document, or what is the page number at the current tag position.

Or another request would be to know how much spacing is left after inserting a Table.

This is something that will never be achievable with docxtemplater, because docxtemplater is only a templating engine: it only knows how to parse the docx format. However, it has no idea on how the docx is rendered at the end: the width, height of each paragraph determines the number of pages in a document.

Since docxtemplater does not know how to render a docx document, (which determines the page numbers), this is why it is impossible to regenerate the page numbers within docxtemplater.

Also, even across different "official" rendering engines, the page numbers may vary. Depending on whether you open a document with Office Online, Word 2013 or Word 2016 or the Mac versions of Word, you can have some slight differences that will, at the end, influence the number of pages or the position of some elements within a page.

The amount of work to write a good rendering engine would be very huge (a few years at least for a team of 5-10 people).

Special character keys with angular parser throws error

The error that you could see is this, when using the tag {être}.

Error: [$parse:lexerr] Lexer Error: Unexpected next character at columns 0-0 [ê] in expression [être].

Since version 3.32.3, this error will not appear anymore if you use the following parser :

const expressionParser = require("docxtemplater/expressions.js");
const doc = new Docxtemplater(zip, {
    parser: expressionParser,
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(/* data */);

Remove proofstate tag

The proofstate tag in a document marks the document as spell-checked when last saved. After rendering a document with docxtemplater, some spelling errors might have been introduced by the addition of text. The proofstate tag is by default, not removed.

To remove it, one could do the following, starting with docxtemplater 3.17.2

const proofstateModule = require("docxtemplater/js/proof-state-module.js");
const doc = new Docxtemplater(zip, {
    modules: [proofstateModule],
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(/* data */);

Adding page break except for last item in loop

It is possible, in a condition, to have some specific behavior for the last item in the loop using a custom parser. You can read more about how custom parsers work here.

It will allow you to add a page break at the end of each loop, except for the last item in the loop.

The template will look like this:

{#users}
The user {name} is aged {age}
{description}
Some other content
{@$pageBreakExceptLast}
{/}

And each user block will be followed by a pagebreak, except the last user.

const expressionParser = require("docxtemplater/expressions.js");

function parser(tag) {
    // We write an exception to handle the tag "$pageBreakExceptLast"
    if (tag === "$pageBreakExceptLast") {
        return {
            get(scope, context) {
                const totalLength =
                    context.scopePathLength[
                        context.scopePathLength.length - 1
                    ];
                const index =
                    context.scopePathItem[
                        context.scopePathItem.length - 1
                    ];
                const isLast = index === totalLength - 1;
                if (!isLast) {
                    return '<w:p><w:r><w:br w:type="page"/></w:r></w:p>';
                }
                return "";
            },
        };
    }
    // We use the expressionParser as the default fallback
    // If you don't wish to use the expressionParser,
    // you can use the default parser as documented here:
    // https://docxtemplater.com/docs/configuration#default-parser
    return expressionParser(tag);
}
const doc = new Docxtemplater(zip, {
    parser,
    paragraphLoop: true,
    linebreaks: true,
});
doc.render();

Encrypting files

Docxtemplater itself does not handle the Encryption of the docx files.

There seem to be two solutions for this:

  • Use a Python tool that does exactly this, it is called msoffcrypto
  • The xlsx-populate library also implements the Encryption/Decryption (algorithms are inspired by msoffcrypto-tool), however, the code probably needs to be a bit changed to work with docxtemplater. Here's the source code.

Assignment expression in template

By using the angular expressions options, it is possible to add assignment expressions (for example {full_name = first_name + last_name} in your template. See following part of the doc.

Changing the end-user syntax

If you find that the loop syntax is a bit too complex, you can change it to something more human friendly (but more verbose). This could be used to have a syntax more similar to what the software "HotDocs" provides.

For example, you could be willing to write loops like this :

{FOR users}
Hello {name}
{ENDFOR}

Instead of

{#users}
Hello {name}
{/}

This can be done by changing the prefix of the loop module, which is a builtin module.

const doc = new Docxtemplater(zip, {
    modules: [
        {
            optionsTransformer(options, doc) {
                doc.modules.forEach(function (module) {
                    if (module.name === "LoopModule") {
                        module.prefix.start = "FOR ";
                        module.prefix.start = "ENDFOR ";
                    }
                });
                return options;
            },
        },
    ],
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(/* data */);

Note that if you don't like the default delimiters which are { and }, you can also change them, for example :

If you prefer to write :

[[FOR users]]
Hello [[name]]
[[ENDFOR]]

You could write your code like this :

const doc = new Docxtemplater(zip, {
    delimiters: { start: "[[", end: "]]" },
    modules: [
        {
            optionsTransformer(options, doc) {
                doc.modules.forEach(function (module) {
                    if (module.name === "LoopModule") {
                        module.prefix.start = "FOR ";
                        module.prefix.start = "ENDFOR ";
                    }
                });
                return options;
            },
        },
    ],
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(/* data */);

Note that it is however not possible to use no delimiters at all, docxtemplater forces you to have some delimiters.

Similarly, for each paid module (image module, ...), you can set your own prefixes as well.

For example, for the image module, if you would like to write {IMG mydata} instead of {%mydata} and {CENTERIMG mydata} instead of {%%mydata}, you can write your code like this :

const ImageModule = require("docxtemplater-image-module");

const opts = {};
opts.centered = false;
opts.getImage = function (tagValue, tagName) {
    console.log("tagName is " + tagName); // if the tag is {%myImage}, tagName is :"myImage"
    return fs.readFileSync(tagValue);
};

opts.getSize = function (/* img, tagValue, tagName */) {
    // img is the value returned by getImage
    return [150, 150];
};

const imageModule = new ImageModule(opts);
imageModule.prefix.normal = "IMG ";
imageModule.prefix.centered = "CENTERIMG ";
const doc = new Docxtemplater(zip, {
    modules: [
        imageModule,
        {
            optionsTransformer(options, doc) {
                doc.modules.forEach(function (module) {
                    if (module.name === "LoopModule") {
                        module.prefix.start = "FOR ";
                        module.prefix.start = "ENDFOR ";
                    }
                });
                return options;
            },
        },
    ],
    delimiters: { start: "[[", end: "]]" },
    paragraphLoop: true,
    linebreaks: true,
});
doc.render(/* data */);

Converting delimiters to other delimiters

It is possible to convert a given template from using some delimiters to some other delimiters.

For example, if you want to convert the following :

Hello {user},

What's up ?

To :

Hello [[user]],

What' up ?

You can do the following :

const PizZip = require("pizzip");
const Docxtemplater = require("./docxtemplater.js");
const fs = require("fs");

function convertDelimiters(input, output, from, to) {
    const zip = new PizZip(fs.readFileSync(input));

    new Docxtemplater(zip, {
        modules: [
            {
                name: "IgnoreModule",
                optionsTransformer: (options, docxtemplater) => {
                    docxtemplater.modules =
                        docxtemplater.modules.filter(
                            function (module) {
                                // You can remove this if condition if you're not using the XlsxModule
                                if (
                                    module.name === "XlsxModule"
                                ) {
                                    Object.keys(
                                        module.prefix
                                    ).forEach(function (key) {
                                        module.prefix[key] =
                                            null;
                                    });
                                    return true;
                                }
                                return module.name === "Render";
                            }
                        );
                    return options;
                },
            },
            // new HtmlModule(),
            // new XlsxModule(),
            // ...,
        ],
        delimiters: from,
        parser: (tag) => {
            return {
                get: () => {
                    return to.start + tag + to.end;
                },
            };
        },
        paragraphLoop: true,
        linebreaks: true,
    }).render();
    fs.writeFileSync(
        "output.docx",
        zip.generate({ type: "nodebuffer" })
    );
}

convertDelimiters(
    "foo.docx",
    "foo-output.docx",
    { start: "{", end: "}" },
    { start: "[[", end: "]]" }
);

Template txt files

Since version 3.33.0, it is possible to template txt files.

The usage is like this :

const TxtTemplater = require("docxtemplater/js/text.js");
const doc = new TxtTemplater("Hello {user}, how are you ?");
const result = doc.render({ user: "John" });
console.log(result); // Shows : "Hello John, how are you ?"

or, if you need the angular expressions parsing engine :

const TxtTemplater = require("docxtemplater/js/text.js");
const expressionParser = require("docxtemplater/expressions.js");
const doc = new TxtTemplater(
    "Hello {fname+lname}, how are you ?",
    {
        parser: expressionParser,
    }
);
const result = doc.render({ fname: "John ", lname: "Doe" });
console.log(result); // Shows : "Hello John Doe, how are you ?"

Debug angular parser

If the values of your tags are resolved incorrectly, you can print out the tag, scope, and result variables when running your parser.

You can use the following snippet

const expressionParser = require("docxtemplater/expressions.js");
const doc = new Docxtemplater(zip, {
    parser(tag) {
        const obj = expressionParser(tag);
        return {
            get(scope, context) {
                console.log(
                    "Evaluating:",
                    tag,
                    " on scope:",
                    scope
                );
                const result = obj.get(scope, context);
                console.log("Result is ", result);
                return result;
            },
        };
    },
    paragraphLoop: true,
    linebreaks: true,
});
doc.render({
    user: {
        name: "Mary",
    },
});

For following template :

{ user.name | uppercase }

It will log :

Evaluating:  user.name | uppercase  on scope {
    user: {
        name: "Mary",
    },
}
Result is MARY

Create "magic" values when using the angular parser

Since version 3.49.0 of docxtemplater, when using the angular parser, it is possible to configure "magic" keys to return some specific values. (This feature cannot be implemented if you use the "docxtemplater/expressions-ie11.js" package).

In your template, if you write :

{#loop}
{__val}
{/}

This will retrieve the val value from the scope that is above the current scope (it retrieves the value of "val" in the scope outside of the loop).

const expressionParser = require("docxtemplater/expressions.js");
const doc = new Docxtemplater(zip, {
    parser: expressionParser.configure({
        evaluateIdentifier(tag, scope, scopeList, context) {
            console.log(context);
            // context contains info about the current tag
            // context.scopePathLength, context.scopePathItem, context.num, and so on
            const matchesParent = /^(_{2,})(.*)/g;
            if (matchesParent.test(tag)) {
                const parentCount =
                    tag.replace(matchesParent, "$1").length - 1;
                tag = tag.replace(matchesParent, "$2");
                if (parentCount >= 1) {
                    for (
                        let i =
                            scopeList.length - 1 - parentCount;
                        i >= 0;
                        i--
                    ) {
                        const s = scopeList[i];
                        if (s[tag] != null) {
                            const property = s[tag];
                            return typeof property === "function"
                                ? property.bind(s)
                                : property;
                        }
                    }
                }
            }
        },
    }),
});

doc.render({
    loop: [
        {
            val: "This value",
        },
    ],
    val: "Other value", // <= This value will be retrieved
});

Table row is breaking across pages

If in your result, you've got rows breaking across pages, this is something that you can fix from your template.

Follow these steps :

  1. Click into a cell in the row
  2. Open the Layout tab under Table Tools and from the Table group select the Properties icon
  3. Select the Row tab
  4. Turn off the option to 'Allow row to break across pages'
  5. Repeat for any other rows in the table
  6. Click on OK
Talk with sales Contact us