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​