DocumentRenderV2Command
Overview
The DocumentRenderV2Command generates professional Word documents (DOCX) from templates with dynamic data binding. It supports advanced features like formatting preservation, table row repetition, paragraph blocks, and optional PDF output.
Key Features:
- ✅ Word document template rendering
- ✅ Formatting preservation (bold, italic, colors, fonts)
- ✅ Table row repetition and multi-row bands
- ✅ Paragraph block repetition
- ✅ Header and footer rendering
- ✅ Optional PDF output
- ✅ Handlebars syntax support (
variable,#if,#each)
When to Use
Use DocumentRenderV2Command for:
- 📄 Loan agreements and contracts
- 📝 Customer statements and reports
- 📋 Certificates and official documents
- 📊 Financial reports with tables
- 📃 Any formal document requiring professional formatting
Syntax
var result = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'loan-agreement-template',
context: JSON.stringify({
customerName: 'John Doe',
loanAmount: 100000,
interestRate: 12.5
}),
isPdfOutput: false
}
});
// result.data contains base64 encoded document
context.generatedDocument = result.data;
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Data.documentName | string | Yes | Name of Word template in DocumentTemplateDefinitiion table |
Data.context | string | Yes | Stringified JSON object with data for template placeholders |
Data.isPdfOutput | boolean | No | If true, returns PDF instead of DOCX (default: false) |
The context parameter must be a stringified JSON string, not an object. Use JSON.stringify() to convert your data object.
Return Value
{
"isSuccessful": true,
"message": "Document 'loan-agreement-template' rendered successfully.",
"data": "JVBERi0xLjQKJeLjz9MK..." // Base64 encoded DOCX or PDF
}
Template Syntax
DocumentRenderV2Command uses Handlebars-style placeholders in Word documents:
- Simple variables: Use curly braces with variable name
- Conditionals: Use
#ifcondition blocks - Loops: Use
#eachor#arrayNamefor iteration - Table repetition: Mark rows with start/end tags
- Nested properties: Use dot notation for object properties
Examples
Example 1: Generate Loan Agreement
Word Template Content:
- Document has placeholders for: customerName, loanAmount, interestRate, tenure
- Table with payment schedule
- Conditional section for collateral (if required)
Generate in Process:
// Prepare repayment schedule data
var scheduleData = [];
for (var i = 1; i <= context.tenure; i++) {
scheduleData.push({
paymentNumber: i,
dueDate: $.format.date($.addMonths(new Date(), i)),
principal: $.format.number(context.principalPerMonth, 2),
interest: $.format.number(context.interestPerMonth, 2),
total: $.format.number(context.monthlyPayment, 2)
});
}
// Generate document
var documentResult = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'loan-agreement-template',
context: JSON.stringify({
agreementDate: $.format.date(new Date()),
customerName: context.customerName,
loanAmount: $.format.number(context.loanAmount, 2),
interestRate: context.interestRate,
tenure: context.tenure,
monthlyPayment: $.format.number(context.monthlyPayment, 2),
collateralRequired: context.loanAmount > 500000,
collateralDescription: context.collateralDescription || 'N/A',
schedule: scheduleData,
signatureDate: $.format.date(new Date())
}),
isPdfOutput: false
}
});
if (documentResult.isSuccessful) {
// Store base64 document
context.loanAgreementDocument = documentResult.data;
// Send via email as attachment
doCmd('SendMailCommand', {
Data: {
email: [context.customerEmail],
subject: 'Your Loan Agreement',
message: 'Please find your loan agreement attached.',
// Attachment would need to be saved as file first
}
});
} else {
throw new Error('Failed to generate loan agreement: ' + documentResult.message);
}
Example 2: Generate Customer Statement
var statement = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'account-statement-template',
context: JSON.stringify({
bankName: 'BankLingo Financial Services',
customerName: context.customerName,
accountNumber: context.accountNumber,
startDate: $.format.date(context.periodStart),
endDate: $.format.date(context.periodEnd),
openingBalance: $.format.number(context.openingBalance, 2),
closingBalance: $.format.number(context.closingBalance, 2),
totalDebits: $.format.number(context.totalDebits, 2),
totalCredits: $.format.number(context.totalCredits, 2),
netChange: $.format.number(context.closingBalance - context.openingBalance, 2),
transactions: context.transactions.map(t => ({
date: $.format.date(t.date),
description: t.description,
amount: $.format.number(Math.abs(t.amount), 2),
isDebit: t.amount < 0,
isCredit: t.amount > 0,
balance: $.format.number(t.balance, 2)
}))
}),
isPdfOutput: true // Generate as PDF for customer download
}
});
// Save to document repository
context.statementDocument = statement.data;
Example 3: Generate Certificate
var certificate = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'account-opening-certificate',
context: JSON.stringify({
customerName: context.customerName,
accountType: context.accountType,
accountNumber: context.accountNumber,
openingDate: $.format.date(context.openingDate),
initialDeposit: context.initialDeposit > 0,
depositAmount: $.format.number(context.initialDeposit, 2),
branchName: context.branchName
}),
isPdfOutput: true
}
});
context.accountCertificate = certificate.data;
Example 4: Generate Report with Multiple Sections
var report = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'monthly-loan-report',
context: JSON.stringify({
reportMonth: $.format.date(new Date(), 'MMMM yyyy'),
generatedDate: $.format.date(new Date()),
// Summary Section
summary: {
totalLoans: context.loans.length,
totalDisbursed: $.format.number(context.totalDisbursed, 2),
totalRepaid: $.format.number(context.totalRepaid, 2),
outstanding: $.format.number(context.outstanding, 2)
},
// Loan Details (table)
loans: context.loans.map(loan => ({
loanId: loan.id,
customerName: loan.customerName,
amount: $.format.number(loan.amount, 2),
disbursedDate: $.format.date(loan.disbursedDate),
status: loan.status,
outstanding: $.format.number(loan.outstanding, 2)
})),
// Delinquent Loans Section
hasDelinquentLoans: context.delinquentLoans.length > 0,
delinquentLoans: context.delinquentLoans.map(loan => ({
loanId: loan.id,
customerName: loan.customerName,
daysOverdue: loan.daysOverdue,
overdueAmount: $.format.number(loan.overdueAmount, 2)
}))
}),
isPdfOutput: false
}
});
context.monthlyReport = report.data;
Advanced Features
1. Formatting Preservation
Unlike V1, DocumentRenderV2Command preserves all formatting:
- Bold, Italic, Underline text
- Font colors and sizes
- Highlights and background colors
- Custom fonts
- Text alignment
If your template has formatted text with placeholders, the rendered document maintains all formatting.
2. Headers and Footers
Placeholders in headers and footers are automatically rendered with data from the context.
3. Table Row Repetition
Tables can repeat rows for each item in an array. Mark the template rows with special tags, and the command will generate one row per array item.
4. Multi-Row Table Bands
You can repeat multiple rows as a group for complex table structures.
5. Nested Properties
Use dot notation to access nested object properties in your data.
Error Handling
Template Not Found
{
"isSuccessful": false,
"message": "Template file not found: loan-agreement-template"
}
Solution: Ensure template exists in DocumentTemplateDefinitiion table with exact name.
Invalid Context JSON
{
"isSuccessful": false,
"message": "Context string is not valid JSON.",
"data": {
"error": "Invalid JSON",
"details": "Unexpected token..."
}
}
Solution: Use JSON.stringify() to convert object to JSON string:
// ✅ Correct
context: JSON.stringify({ name: 'John' })
// ❌ Wrong
context: { name: 'John' }
Missing Required Property
{
"isSuccessful": false,
"message": "Missing required property 'documentName'."
}
Solution: Ensure all required parameters are provided.
Best Practices
1. Always Stringify Context
// ✅ Good
var doc = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'template',
context: JSON.stringify({
name: context.customerName,
amount: context.loanAmount
})
}
});
// ❌ Bad - Will fail
var doc = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'template',
context: {
name: context.customerName
}
}
});
2. Format Data Before Passing
// Format numbers, dates, and currencies BEFORE passing to template
context: JSON.stringify({
amount: $.format.number(rawAmount, 2), // "10000.00"
date: $.format.date(rawDate), // "Jan 15, 2026"
currency: $.format.currency(rawAmount) // "₦10,000.00"
})
3. Test Templates Before Production
// Test template rendering with sample data
var testDoc = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'new-template',
context: JSON.stringify({
testField1: 'Test Value 1',
testField2: 'Test Value 2',
testArray: [
{ item: 'Item 1', value: 100 },
{ item: 'Item 2', value: 200 }
]
})
}
});
if (!testDoc.isSuccessful) {
throw new Error('Template test failed: ' + testDoc.message);
}
4. Handle Large Documents
For large documents, consider generating asynchronously or in background jobs.
5. Store Generated Documents
var doc = doCmd('DocumentRenderV2Command', {
Data: {
documentName: 'loan-agreement',
context: JSON.stringify(loanData)
}
});
if (doc.isSuccessful) {
// Store base64 document in context for later use
context.generatedDocument = doc.data;
context.documentName = 'LoanAgreement_' + context.loanId + '.docx';
}
Comparison: V1 vs V2
| Feature | DocumentRenderCommand (V1) | DocumentRenderV2Command (V2) |
|---|---|---|
| Formatting Preservation | ❌ Lost | ✅ Preserved |
| Table Row Repetition | ✅ Basic | ✅ Advanced (multi-row bands) |
| Paragraph Blocks | ❌ No | ✅ Yes |
| PDF Output | ❌ No | ✅ Yes |
| Context Parameter | Object | Stringified JSON |
Recommendation: Use DocumentRenderV2Command for all new development.
Performance Considerations
| Document Size | Complexity | Avg. Render Time |
|---|---|---|
| Small (1-2 pages) | Simple variables only | 200-500ms |
| Medium (3-10 pages) | Tables + conditionals | 500ms-2s |
| Large (10-50 pages) | Multiple tables + loops | 2-10s |
| Very Large (50+ pages) | Complex nested structures | 10s+ |
Tips for Better Performance:
- Keep templates lean (avoid unnecessary formatting)
- Minimize nested loops
- Pre-process data (format before passing to command)
- Use pagination for very large datasets
- Consider async generation for reports over 20 pages
Related Commands
- RenderHtmlCommand - Generate HTML content
- SendMailCommand - Email documents as attachments
Troubleshooting
Issue: Placeholders Not Replaced
Cause: Context data structure doesn't match template placeholders.
Solution: Ensure context structure matches template expectations with proper nesting.
Issue: Table Rows Not Repeating
Cause: Missing array data or incorrect template markup.
Solution: Ensure your context includes the array data and template has proper row markers.
Issue: Formatting Lost
Cause: Using V1 instead of V2.
Solution: Switch to DocumentRenderV2Command.
Issue: "Template not found" Error
Cause: Template name mismatch.
Solution: Check exact name in database:
SELECT Name FROM DocumentTemplateDefinitiion;
Use exact name (case-sensitive).