Skip to main content

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

ParameterTypeRequiredDescription
Data.documentNamestringYesName of Word template in DocumentTemplateDefinitiion table
Data.contextstringYesStringified JSON object with data for template placeholders
Data.isPdfOutputbooleanNoIf true, returns PDF instead of DOCX (default: false)
Important

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 #if condition blocks
  • Loops: Use #each or #arrayName for 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

FeatureDocumentRenderCommand (V1)DocumentRenderV2Command (V2)
Formatting Preservation❌ Lost✅ Preserved
Table Row Repetition✅ Basic✅ Advanced (multi-row bands)
Paragraph Blocks❌ No✅ Yes
PDF Output❌ No✅ Yes
Context ParameterObjectStringified JSON

Recommendation: Use DocumentRenderV2Command for all new development.

Performance Considerations

Document SizeComplexityAvg. Render Time
Small (1-2 pages)Simple variables only200-500ms
Medium (3-10 pages)Tables + conditionals500ms-2s
Large (10-50 pages)Multiple tables + loops2-10s
Very Large (50+ pages)Complex nested structures10s+

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

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).

See Also