Generate Documents from Salesforce Related Lists with Dochly
What are related lists in documents?
In Salesforce, a related list is a child object linked to a parent record — for example, Opportunity Products linked to an Opportunity, or Contacts linked to an Account. When you generate a document from the parent record, you can include a dynamic table that repeats one row for each child record in the related list.
This is fundamentally different from a merge field. A merge field pulls one value from one field on one record. A related list table pulls multiple fields from multiple records and renders them as a structured table — automatically expanding or contracting based on how many child records exist.
Generate one table row per related child record. The table expands automatically — if an Opportunity has 3 products, you get 3 rows. If it has 15 products, you get 15 rows. No manual counting or blank rows.
They don't create static tables with a fixed number of rows. If you add a static 5-row table and the Opportunity has 7 products, 2 products won't appear. Always use REPEAT blocks for variable-length data.
Common related lists to include in documents
The REPEAT syntax
Dochly uses a {REPEAT} block to mark which rows in a table should repeat for each related record. Everything between {REPEAT} and {END REPEAT} is generated once per related record.
{REPEAT RelatedListAPIName}
Data row — one row per related record
{{RelatedObject.Field1}} | {{RelatedObject.Field2}} | {{RelatedObject.Field3}}
{END REPEAT}
Totals row — OUTSIDE the repeat block
Key rule: the header row and totals row always go outside the REPEAT block. Only the repeating data row goes inside. If you put the header inside the repeat block, a new header row appears before every data row — one of the most common related list mistakes.
Product | Qty | Price ← header OUTSIDE
{REPEAT OpportunityLineItems}
{{OpportunityLineItem.Name}} | {{OpportunityLineItem.Quantity}} | {{OpportunityLineItem.UnitPrice}}
{END REPEAT}
✗ INCORRECT — header inside repeat (repeats for every row):
{REPEAT OpportunityLineItems}
Product | Qty | Price ← header INSIDE — wrong
{{OpportunityLineItem.Name}} | {{OpportunityLineItem.Quantity}} | {{OpportunityLineItem.UnitPrice}}
{END REPEAT}
Step-by-step: adding a related list table to your template
Identify the related list API name
The REPEAT block requires the API name of the related list — not its display label. For standard Salesforce related lists, the names are well known. For custom related lists, find the API name in Salesforce Object Manager.
To find a custom related list API name: Setup → Object Manager → [Child Object] → Fields & Relationships → find the lookup field to the parent → the Child Relationship Name is the value to use in your REPEAT block.
| REPEAT name | Related list | Used for |
|---|---|---|
| OpportunityLineItems | Opportunity Products | Proposals, quotes, invoices |
| Contacts | Account Contacts | Account summaries, org docs |
| Cases | Account Cases | Support summaries, reviews |
| ActivityHistories | Activity History | Meeting notes, account reviews |
| ContractLineItems | Contract Line Items | Renewals, amendments |
| CustomObject__r | Custom child object | Any custom relationship |
Add the table structure in the template editor
In the Dochly template editor, insert a table at the position where the related list data should appear. Set up the columns you need — typically you'll have 3–6 columns depending on the data. Set the header row with column labels.
Example for a line items table with 5 columns:
Apply any styling you want to the header row now — background color, bold text, font size. The header row is outside the REPEAT block so it won't repeat.
Add the REPEAT block around the data row
Below the header row, add the data row. Wrap the data row with the REPEAT and END REPEAT tags — place them directly before and after the data row cells, not around the entire table.
{REPEAT OpportunityLineItems}
[data row cells go here — step 4]
{END REPEAT}
Add merge fields inside the REPEAT block
Inside the data row, insert merge fields for each column using the related object's field API names. Use the merge field picker in the toolbar and navigate to the related object to find the correct fields.
{REPEAT OpportunityLineItems}
{{OpportunityLineItem.Name}} | {{OpportunityLineItem.Quantity}} | {{OpportunityLineItem.UnitPrice | currency}} | {{OpportunityLineItem.Discount}}% | {{OpportunityLineItem.TotalPrice | currency}}
{END REPEAT}
Always apply | currency formatting to money fields and right-align numeric columns for professional presentation.
Add totals and summary rows
Below the END REPEAT tag, add a totals row. This row is outside the repeat block — it appears once at the bottom of the table regardless of how many line items there are. Pull total values from the parent record fields (not the line items):
Subtotal: {{Opportunity.Amount | currency}}
Discount: {{Opportunity.TotalOpportunityQuantity}}
Tax: {{Opportunity.Tax_Amount__c | currency}}
Total Due: {{Opportunity.GrandTotal__c | currency}}
Handle empty related lists gracefully
If the related list has zero records, the REPEAT block generates zero rows — the table header appears but the body is empty. For documents where an empty table looks unprofessional, wrap the entire table in a conditional block:
[Entire table including header, REPEAT block, and totals]
{ELSE}
No products have been added to this opportunity.
{END IF}
This hides the empty table completely and shows a fallback message when no related records exist.
Test and preview
Preview the template from a record that has multiple related records in the list — at least 3 to verify the table expands correctly. Test with these scenarios:
- A record with 1 related record — confirm single row renders correctly
- A record with 5+ related records — confirm all rows appear, no records are truncated
- A record with 0 related records — confirm the empty state is handled gracefully
For troubleshooting table issues: Troubleshooting document generation errors
Field reference by related list
These are the most commonly used fields from the most common Salesforce related lists. Use these as a reference when building your repeating table columns.
| Merge field | Label | Notes |
|---|---|---|
| {{OpportunityLineItem.Name}} | Product Name | Name of the product or line item |
| {{OpportunityLineItem.Quantity}} | Quantity | Number of units — format as integer |
| {{OpportunityLineItem.UnitPrice}} | Unit Price | Price per unit — apply | currency |
| {{OpportunityLineItem.TotalPrice}} | Total Price | Qty × Unit Price — apply | currency |
| {{OpportunityLineItem.Discount}} | Discount % | Discount percentage — append % symbol |
| {{OpportunityLineItem.Description}} | Description | Product description — may be blank |
| {{OpportunityLineItem.ServiceDate}} | Date | Service/delivery date — apply date format |
| Merge field | Label | Notes |
|---|---|---|
| {{Contact.FirstName}} | First Name | Contact first name |
| {{Contact.LastName}} | Last Name | Contact last name |
| {{Contact.Title}} | Title | Job title — may be blank |
| {{Contact.Email}} | Primary email address | |
| {{Contact.Phone}} | Phone | Direct phone number |
Sorting and filtering related records
By default, related records appear in the order they are returned by Salesforce — typically insertion order. You can control the order and optionally filter which records appear using REPEAT block modifiers.
{{OpportunityLineItem.Name}} | {{OpportunityLineItem.TotalPrice | currency}}
{END REPEAT}
{{OpportunityLineItem.Name}} | {{OpportunityLineItem.TotalPrice | currency}}
{END REPEAT}
{{Case.CaseNumber}} | {{Case.Subject}} | {{Case.CreatedDate | date: "MMM d, yyyy"}}
{END REPEAT}
Sorting and filtering use the Salesforce field API name — not the field display label. Always verify the API name in Object Manager before using it in a WHERE or ORDERBY clause. Invalid field names cause the REPEAT block to fail silently.
Common related list errors
The header row is inside the REPEAT block instead of outside it. Move the header row above the {REPEAT} tag — it should appear once regardless of how many records exist.
The related list API name in the REPEAT tag is incorrect. Check Setup → Object Manager → [Child Object] → Fields & Relationships → lookup field → Child Relationship Name.
The REPEAT and END REPEAT tags are missing or misplaced — the data row is not inside the repeat block. Confirm both tags are present and correctly wrapping the data row.
Extra empty rows were added inside the REPEAT block. Only one data row should exist between {REPEAT} and {END REPEAT}. Delete any extra rows inside the repeat block.
Frequently asked questions
You can now include dynamic related list tables in any Dochly template. Next in this series: Generate a document from any Salesforce record — how generation works across all standard and custom objects beyond Opportunities.
Rated 5 stars · Native Salesforce app · Free to install