Word Report Generation in Salesforce. Part 1.
Template-based docx report creation in Salesforce. We will use docx-templates liabrary embedded to the VisualForce page to achive this. Most commonly this lib is used in server side, but it has a browser polyfill, so we can use it right from the browser. There will be 2 parts, in the second part we will update our code to show the preivew of the generated template.
Why docx-templates?
- Write documents naturally using Word, just adding some commands where needed for dynamic contents
- Express your data needs (queries) in the template itself (QUERY command), in whatever query language you want (e.g. in GraphQL). This is similar to the Relay way™: in Relay, data requirements are declared alongside the React components that need the data
- Execute JavaScript snippets (EXEC command, or ! for short)
- Insert the result of JavaScript snippets in your document (INS, = or just nothing)
- Embed images, hyperlinks and even HTML dynamically (IMAGE, LINK, HTML). Dynamic images can be great for on-the-fly QR codes, downloading photos straight to your reports, charts… even maps!
- Add loops with FOR/END-FOR commands, with support for table rows, nested loops, and JavaScript processing of elements (filter, sort, etc)
- Include contents conditionally, IF a certain JavaScript expression is truthy
Setup
- Download the docx-templates (Polyfilled browser-ready bundle) and load it to the Static Resource
- Create an empty Visualforce page.
Code
We will use Visualforce becaue as for now Lightning Web Components fraemwork doesn’t allow us to import Static Resource as module and code is too long to deploy it in separate .js file.
In this example we are using Visualforce page with imported docx-templates.
WordReportGenerator.page
<apex:page>
<apex:slds />
<script type="module">
import { createReport } from '{!URLFOR($Resource.docxtemplates)}';
document.addEventListener('DOMContentLoaded', () => {
const inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', onTemplateChosen, false);
});
async function onTemplateChosen() {
console.log('Template chosen');
const template = await readFile(this.files[0]);
console.log('Creating report (can take some time) ...');
const report = await createReport({
template,
data: {
name: 'John',
surname: 'Appleseed',
CONSTANT: 'information from the constant',
},
cmdDelimiter: ['«', '»']
});
saveDataToFile(
report,
'report.docx',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
);
}
function readFile(fd) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result);
};
reader.readAsArrayBuffer(fd);
});
}
function saveDataToFile(data, fileName, mimeType) {
const a = document.createElement('a');
const blob = new Blob([data], { type: mimeType });
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
};
</script>
<div class="slds-scope">
<input class="slds-m-around_medium" id="fileInput" type="file"/>
</div>
</apex:page>
Magic happens in:import { createReport } from '{!URLFOR($Resource.docxtemplates)}';
after that we are able to set an event listener to the input with type = ‘file’ and assign onTemplateChosen() function.
const report = await createReport({
template,
data: {
name: 'John',
surname: 'Appleseed',
CONSTANT: 'information from the constant',
},
cmdDelimiter: ['«', '»']
});
The main block from our code example, it creates a report from the template. We are passing template (docx file with tags), data (actual data that will be displayed in the report.docx). After generation the report will be autmatically downloaded to your default Downloads folder.
How it works
Example of template.docx:
Previously we have set cmdDelimiter: [’«’, ‘»’] in createReport example, so our template variables shoud be wrapped in ‘«’ ‘»’.
I have added Visualforce component to the page:
The result that was generated by our page. In the second part we will implement the preview feature, image generation and access to DB. Example of the report.docx: