1

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());
edi9999
  • 19,701
  • 13
  • 88
  • 127
Mario Varchmin
  • 3,704
  • 4
  • 18
  • 33

2 Answers2

1

Thanks for taking the time to explain your issue in detail.

I've updated the documentation to put the doc.render() after the console.log, and I added a note that it is optional for retrieving the tags of the document.

About your question, there is currently no way to render the same docxtemplater instance with multiple datasets, you need to use a new pizzip instance and a new Docxtemplater instance (you can keep the same inputBuffer however). The cause of this is because I don't think that there is a way to clone a pizzip instance easily. But this idea always was in my mind, notably for docxtemplater version 4.

edi9999
  • 19,701
  • 13
  • 88
  • 127
0

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());
Mario Varchmin
  • 3,704
  • 4
  • 18
  • 33