Search code examples
javascriptdocxtemplater

How to render docxtemplater multiple times with different data sets


I use docxtemplater to replace tags in Word documents (which I load from the cloud) with actual values.

The Word documents I work with contain arbitrary tags, so I first need to inspect a Word document and get a list of all tags it contains. For that I use the InspectModule, which is set as an option for docxtemplater.render(). I then query a service, where I use the tags as parameters of a dynamic query. Lastly, I replace the tags with the various query results by calling docxtemplater.setData(myData) followed by (again) docxtemplater.render().

The problem is, when I call docxtemplater.render() with the InspectModule, not only does the module get all the tags (which is good), it also replaces all tags in the Word document with the string "undefined" (which is bad for my purpose), because I want to replace the tags not with the string "undefined", but with the results of my query transformed into a data object.

What is the best approach to work around this problem (in essence, I want to be able to call render() multiple times)? Reload the Word document from the cloud and start with a new docxtemplater to render() again with the queried data? Deep-copy the docxtemplater object before calling render() the first time, so I have a "fresh" copy of the docxtemplater object, that I can use for the second render() call? Or can I call render() with a parameter, so that it does not modify the document, or is there a reset() method, that sets the docxtemplater object back to the state before the execution of the render() method? Or are there other, better options? Thanks!

Code: this gets me all the tags, and replaces all tags in the Word document with the string "undefined".

const iModule = InspectModule();
const options = {modules: [this.iModule]};
const data = await fetch("something.docx");
const zip = new PizZip(data);
const document = new Docxtemplater(zip, options);
document.render();
const tags = Object.keys(this.iModule.getAllTags());

Solution

  • I found out that the example given in the docxtemplater FAQs (https://docxtemplater.readthedocs.io/en/latest/faq.html#get-list-of-placeholders) was misleading me. In fact, you can simply omit the call to doc.render(), and you still get all tags. So, the problem can be solved like this:

    const iModule = InspectModule();
    const options = {modules: [this.iModule]};
    const data = await fetch("something.docx");
    const zip = new PizZip(data);
    const document = new Docxtemplater(zip, options);
    const tags = Object.keys(this.iModule.getAllTags());