alonrbar / easy-template-x Goto Github PK
View Code? Open in Web Editor NEWGenerate docx documents from templates, in Node or in the browser.
License: MIT License
Generate docx documents from templates, in Node or in the browser.
License: MIT License
Hello everyone,
I have been trying to display an array inside if condition.
Here is the template I use inside myc docx file:
{#participants}
{#display}
{name}
{#list}
Name : {name}
Surname : {surname}
{/list}
{/}
{/ participants }
And here is the data I pass to the template:
const data = {
"participants": [
{
"display": true,
"name" : "bob",
"list": [
{ "no": 1, "name": "Bryson", "surname": "Pike" },
]
},
{
"display": true,
"name" : "alice",
"list": [
{ "no": 3, "name": "Charis", "surname": "Hilton" },
{ "no": 4, "name": "John", "surname": "Plant" },
]
},
{
"display": false,
"name" : "bruno",
"list": [
{ "no": 6, "name": "Beatriz", "surname": "Schmitt" },
{ "no": 7, "name": "Fionn", "surname": "Lyons" },
{ "no": 8, "name": "Pedro", "surname": "Compton" }
]
}
]
}
const handler = new TemplateHandler();
const doc = await handler.process(templateFile, data);
And here is a screenshot of the output.docx file generated :
As you can see the name displayed is the name of participants and not the in in the list, also no surname is displayed..
Am I doing something wrong in the template or is this not supported with easy-template-x ?
PS: if I remove the condition {#display} {/} it works fine and displays the right values, so it seems that the problem is doing a loop inside a condition.
Thank you!
@alonrbar I worked quite a while at your project today and changed a few things, here is what I've done:
PluginContent
to prevent type errors while creating new pluginsYou can find my changes here https://github.com/bbit-cloud/easy-template-x.
I don't know if you are happy with those changes because I touched nearly every file, if you think this all makes sense I am happy to provide a pull request :)
It's possible to keep {tag} if the value is null, empty string, etc? For single value I just replace do replacing like this:
orderDate: currentClaim.orderDate ? moment(currentClaim.orderDate).format("DD.MM.YYYY") : "{orderDate}",
But how do it for arrays?
{#reviews}{position} {submitted} {acceptanceText} {fullName}{/reviews}
Hi all,
This is a question since I have some issues rendering content in a custom plugin, not an issue with the library itself I guess, but maybe some with more word-xml experience has an idea....
I am currently working on a plugin to render prosemirror editor content to a word template, this is required in my project since some rich text parts have to be rendered dynamically.
It was not an issue to render simple styles like bold, italic or some color for text nodes. But as soon as I try to render some pStyles
they get not properly applied.
For example if i try to render headings the following output is generated:
But it should look like this:
As you can see, the Heading1
style is applied properly, Heading2
and Heading3
are not working.
A similar issue happens with Bullet and ordered lists:
As you can see here, the XML are basically identically... Adding all the IDs so they match up with de document does not change a thing.... As you can see in the generated styles the numId
with value 1
is ignored here
Manually added styles:
<w:p w14:paraId="531E0080" w14:textId="5F7940E5" w:rsidR="00F06626" w:rsidRPr="00F06626" w:rsidRDefault="00F06626" w:rsidP="00F06626">
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
</w:pPr>
<w:r w:rsidRPr="00F06626">
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
<w:t>Bullet list 1</w:t>
</w:r>
</w:p>
<w:p w14:paraId="49BB712D" w14:textId="1F7AE020" w:rsidR="00F06626" w:rsidRPr="00F06626" w:rsidRDefault="00F06626" w:rsidP="00F06626">
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
</w:pPr>
<w:r w:rsidRPr="00F06626">
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
<w:t>Bullet list 2</w:t>
</w:r>
</w:p>
generated styles:
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
<w:t xml:space="preserve">Bullet list 1</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:lang w:val="en-US"/>
</w:rPr>
<w:t xml:space="preserve">Bullet list 2</w:t>
</w:r>
</w:p>
Has anyone an idea what I can to to fix this?
Thanks a lot!
I find that it would be nice to get a list of actual tags that exist in the document.
This way I know which tags to generate data for - in some cases it can save quite a lot of time.
Is this possible?
Is it possible to detect tags that don't have any corresponding data to be replaced into.
For example:
Data:
{
"Beers": [
{ "Brand": "Carlsberg" },
{ "Brand": "Leaf Blonde" },
{ "Brand": "Weihenstephan" }
]
}
Tags in my template:
{#Beers}{Brand}_{Price}${/Beers}
Can I detect that {Price} doesn't have any data and get that tag?
Hi,
Can I add a base64 image instead of file?
"Kung Fu Hero": {
_type: "image",
source: base64 string,
format: MimeType.base64,
width: 200,
height: 200
}
like this
Please provide the syntax for adding cells in a row from a loop or conditionally.
Hi, can you make a simple demo for in the browser,
I've reached a point where the file .docx isn't recognized, if you try to execute check the console output
easyexample.zip
Hi,
I'm having some trouble compiling. I'm getting a bunch of errors in the types files.
https://hastebin.com/ajebujisaz.cs
I added the library to an Angular 8.0 project.
I can see that you support binary, but how exactly does one go about embedding an image from the JSON data into the template?
Many thanks!
I have the following code to test and parse the file test.docx. But seem weird that the file is corrupted when we have the content inside beginning with the word certificate, and if I remove the leading certificate word inside the docx file. The convert is success. Can anybody explain?
const { TemplateHandler } = require("easy-template-x");
const fs = require("fs");
const unoconv = require('awesome-unoconv');
const parseDoc = async () => {
const handler = new TemplateHandler();
try {
const templateFile = fs.readFileSync('test.docx');
const data = {
name: 'test',
unit_number: '1111',
};
const updatedDoc = await handler.process(templateFile, data);
fs.writeFileSync('test.docx', updatedDoc); // success convert but when write the file it become corrupted
await unoconv.convert('test.docx', 'test.pdf');
} catch (error) {
// thow error here
console.log(error)
}
}
parseDoc();
Error:
The document 'file:///var/www/sparebox-admin/test.docx' could not be opened.
at ChildProcess.<anonymous> (/var/www/sparebox-admin/node_modules/awesome-unoconv/dist/converter.js:147:23)
at ChildProcess.emit (events.js:198:13)
at maybeClose (internal/child_process.js:982:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
test.docx: this file would cause an error with the word "certificate" leading
test.docx: this file is successful without the word "certificate" leading
Version:
"easy-template-x": "^1.0.1"
and "easy-template-x": "^2.1.0"
"awesome-unoconv": "^1.0.1"
Excellent library but unfortunately I need to generate forms complete with filled in content controls.
Any idea how this could be done?
Hi, very interested in this library, but a few questions.
Suppose this data structure:
const data = {
posts: [
{ author: 'Alon Bar', text: 'Very important\ntext here!', fans: [{ text: 'A' }, {text: 'B'}] },
{ author: 'Alon Bar', text: 'Forgot to mention that...', fans: [{ text: 'A' }, {text: 'B'}] }
]
};
How do I fix this template:
{#posts}
Author: {author}
{text}
{#fans}
{text} < I want the post text here
{text} < I want the fan text here
{/fans}
{/posts}
Let's ignore how rubbish an example this is... but the principle remains: how would I target a the parent text
and the new child text
from within the second loop?
Many thanks
Hi,
Did you test this against Edge? Can't seem to get it to work, nor does the live demo work on Edge. Firefox seems to run OK, not sure about Chrome.
Getting
0: Invalid calling object easy-template-x.js (1859,1)
Presumably in the following code block
async getDocument() {
if (!this._document) {
const xml = await this.zip.getFile(this.documentPath).getContentText();
this._document = this.xmlParser.parse(xml);
}
return this._document;
}
First of all congratulations for this library.
After testing your library I discovered a bug. When you put a hyperlink with a hashtag, the file crashes.
Corrupto.docx
This file doesn't work, because it has a hashtag in the hyperlink.
Funciona.docx
But this file works because it doesn´t have a hashtag in the hyperlink.
Could you check it? thanks 😊
I got a solution based on docxtemplater
here, so I think it should be not hard to achieve. Maybe a function named merge
can be added to TemplateHandler
:D
Hi,
It looks like a very useful plugin.
I want to try this in a standard Javascript in browser, without typescript, import, export.
Your browser version is in Typescript.
Can you provide the standard JS to work in browser and code snippet?
Thanks,
Muthu
Is there any way to replace variables in the header of a word file, when using a custom template on the demo page it did not replace any of the header text.
I'd like to insert spreadsheets, but not sure how it's possible?
I'm guessing maybe with rawXML, but I can't figure out how to start..
In Libreoffice Writer it can be done manually by choosing Insert > Object > Ole Object > Create new LibreOffice 7 Spreadsheet.
I suppose it's similar in Microsoft Word.
I've attached an example docx for reference.
My data (received from backend API) is organized as hierarchical content. How can access an object property within a template file
Something like {project.client.title}
I found no way to make it work
Browser example for the README.md file:
import {TemplateHandler} from 'easy-template-x';
import save from 'save-file';
import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
loadFile = (url,callback) => {
JSZipUtils.getBinaryContent(url,callback);
}
myEasyTemplate = () => {
this.loadFile("myTemplate.docx",function(error,content){
if (error) { throw error };
const data = {
posts: [
{ author: 'Easy', text: 'Very important\ntext here!' },
{ author: 'Easy', text: 'Forgot to mention that...' }
]
};
const handler = new TemplateHandler();
handler.process(content, data).then(doc =>
{
save.sync(doc, "easy-output.docx");
});
})
}
First of all.. Thank you so much for this library!
I´ve encounter a possible bug when we write something like {#table}{Property1}{#images}{image}{/images}{Property2}{/Table}. All the information is visible but each image is separated with a row with the same information from property1 and property2.
Already tried to separate the tags with new line but with no success..
Some prints below.. Any help is appreciated, thanks!
Hi, it's me again. Now I'm having a new trouble wich is that I have a nested array with images inside and when I print the document it just writes [object Object]
.
My array looks like this:
items [ name: 'product 1', description: 'Description for product 1 here....', image: { _type: 'image', source: <source> format: 'image/png', width, height, }, name: 'product 2', description: 'Description for product 2 here....', image: { _type: 'image', source: <source> format: 'image/png', width, height, }, ]
and my docx document looks like this:
{#items} {name} {description} {image} {/items}
It prints the name and description correctly, but for the image prints [object Object]
Help!:(
I added an image to a list but only show blank box in word.
{ "Brand": "Carlsberg",
"Price": 1 ,
"image": {
_type: "image",
source: fs.readFileSync("./res/image-plugin-out.png"),
format: "image/png",
width: 371,
height: 387
}
}
Any help would be grateful.
François
Are there any plans to support conditions?
We used docxtemplater
before but we would like to switch to this project because of the ability to add custom plugins (we need this feature to properly render Deltas from the quill editor).
Of course I can try to implement conditions with a plugin, but I think this would be a nice general feature for this project :)
I am migrating my project from webpack to vite. When building the project for production using Rollup under the hood I get the following error:
require is not defined
The reason is that Vite works only with ES modules and is not compatible with CommonJS. Diving deeper I stated that require
is used in src/compilation/scopeData.ts:
const getProp = require("lodash.get");
As the result, ESM version of this package contains this require
in the build. In order to fix the issue the dependency should be imported like this:
import getProp from 'lodash.get';
As a quick workaround I managed to apply the following patch to 3.0.0
using patch-package:
diff --git a/node_modules/easy-template-x/dist/es/easy-template-x.js b/node_modules/easy-template-x/dist/es/easy-template-x.js
index 641554d..f0d43f0 100644
--- a/node_modules/easy-template-x/dist/es/easy-template-x.js
+++ b/node_modules/easy-template-x/dist/es/easy-template-x.js
@@ -1163,7 +1163,7 @@ class DelimiterSearcher {
}
-const getProp = require("lodash.get");
+import getProp from 'lodash.get';
class ScopeData {
static defaultResolver(args) {
Hi @alonrbar,
Me again ;) This has not a high priority for me personally, but it might become an issue for other users.
I am currently implementing new plugins. Adding the plugins directly in my fork works great, but if I try to do this from "outside" in my example from my angular application the following error occurs:
TypeError: Class constructor TemplatePlugin cannot be invoked without 'new'
I had no time to dig into this issue further, I have to prepare a release of the new version of our app and will stick to implement it in my fork.
I will update this issue as soon as I found something helpful.
I'm trying to compile easy-template-x for using it on the browser but all my attempts failed.
Is there a precompiled .js file or an explanation to compile and include it on the borwser?
Thanks so much in advance.
Hello,
it is any way to insert tables like this: http://officeopenxml.com/WPtable.php to document using rawXml plugin? When i create that table and use rawXml plugin, document after generating is corrupted.
Best regards
Hello. I have an error "Binary type 'Buffer' is not supported." when I call handler.process. But handler.getText and getXml work fine.
const templateFile = await fs.readFileSync( exportDir + fileName);
const data = {
Country: country,
};
const handler = new TemplateHandler({
delimiters: {
start: '{',
end: '}'
}
});
const doc = await handler.process(templateFile, data);
I am trying a basic test run with this package. But when I try to run the code, the output is just long line of string.
source: test.docx
ouutput file (generated): output.docx
Code:
const fs = require("fs");
const path = require("path");
const { TemplateHandler } = require("easy-template-x");
const templateFile = fs.readFileSync(path.join(__dirname, "test.docx"));
// 2. process the template
const data = {
name: "sha",
bio: "bla"
};
const handler = new TemplateHandler();
const gendoc = async () => {
const doc = await handler.process(templateFile, data);
fs.writeFileSync("myTemplate - output.docx", doc);
};
// 3. save output
gendoc();
Node version: 16.15.1
I have a question as to how can one add a hyperlink?
Like it is done in this project docx-templates :- Links
I get "An accessor cannot be declared in an ambient context." in multiple files when running npm start.
Is the issue that I am running on a too old version of typescript or something else?
I am currently running Typescript 2.7.2 and Angular 6.1.
First of all thanks for this amazing library. Great work.
Is there a chance to add convert to pdf feature? Preferably without 3rd party libraries (LibreOffice etc.)
I found this library but it's too slow with buffer
Hello,
I have a question.
In my template, each row of data is represented by one table.
But what I'm not able to achieve is to remove empty lines caused by the Loop start tag & the Loop end tag.
I prepared a simplified demo https://codesandbox.io/s/easy-template-x-demo-forked-m6061 where you can try it.
At the bottom is a preview of what is generated and what I what to achieve.
The only problem is empty lines between tables.
Do you think that this problem can be somehow solved?
Thank you
Greetings!
First of all, thank you very much for all the work you put in thus far. I really like the concept and I think it can be greatly expanded upon. For my current use case, I need to read the docx template, and then extract the tags, but in a hierarchical order.
Could you point me in the right direction in terms of how to achieve this? I tried digging into the libraries depths but was a little overwhelmed by the complexity since I have no experience working with XML.
As an example though, say we have the following tags in a template (which I know I can get from parseTags)
{color}
{#master}
{author}
{#nest_1_cond}
{copyright}
{/}
{#nest_2_cond}
{someVar}
{/}
(/)
(subject)
this should result in the following object
{
color: "",
master: {
author: "",
nest_1_cond: {
copyright: "",
},
nest_1_cond: {
someVar: "",
},
},
subject:""
}
I know there are some problems with this right of the bat. For example,
I am half sure that this functionality is already there, at least in reverse since you somehow need to find all the tags and all the loops for the loop functionality. But I am unsure on how to reverse construct an object from that, if that is even practicable. If you have any suggestions, ideas or further reading - I 'll gladly take it
for example:
i have array of images like
attachments: [{
_type: 'image',
source: readFileSync('hero.png').buffer,
format: 'images/png',
width: 200,
height: 200,
}, {...}, {...}],
how should i write the template file?
My word document has a placeholder which is <<insert>>
. Can we configure the placeholder as <<>> instead of {} ?
I have a simple .docx file that only contains
{Last Name}, {First Name}: {Address}
When I call
await handler.parseTags(this.file.value)
I get an error:
core.js:6014 ERROR Error: Uncaught (in promise): Error: Tag '' does not match any of the known prefixes.
Error: Tag '' does not match any of the known prefixes.
at TagParser.processTag (easy-template-x.js:2419)
at TagParser.parse (easy-template-x.js:2348)
at TemplateCompiler.parseTags (easy-template-x.js:2477)
at TemplateHandler.parseTags (easy-template-x.js:4441)
at resolvePromise (zone-evergreen.js:797)
at zone-evergreen.js:707
at rejected (tslib.es6.js:71)
at ZoneDelegate.invoke (zone-evergreen.js:359)
at Object.onInvoke (core.js:39698)
at ZoneDelegate.invoke (zone-evergreen.js:358)
at Zone.run (zone-evergreen.js:124)
at zone-evergreen.js:855
at ZoneDelegate.invokeTask (zone-evergreen.js:391)
at Object.onInvokeTask (core.js:39679)
But if I remove {Address}
then it parses the tags fine.
I'm not having any success replacing tags in the header and footer of documents allthough it should be possible since version 0.12. Can someone provide a working example?
Hi! I'm having some trouble with some nested arrays with objects. In my document I do this:
{#array} {property1} {property2} {#nestedArray} {propertyOneOfNestedArray} {/nestedArray} {/array}
Obviously this is an example, but this is some kind of example that I'm trying to do.
Sorry for my english.
Hey guys,
i was trying to replace an image in a react-app by following the documentation. Text replacing is working fine but image replacing is just not working.
You can have a look at my codesandbox. If you remove the image property in the data object its working but when i try to replace with image property, it´s giving me the following error message (Binary type 'Promise' is not supported). So im wondering if there is something wrong with my image format or if there´s another problem. I tried with blob and ArrayBuffer.
Hope you guys can help me here.
Thanks
PS: Since downloading contents at codesandbox is not working anymore i just logged the error.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.