Skip to main content

Tables in Templates - Dynamic Table Guide

Tables are fundamental components of professional documents, providing structured presentation of data for easy comparison, reference, and analysis. PDF4me's document generation engine efficiently creates dynamic tables populated with data from your sources.


Multi-Column Table Structure

Generate tables with multiple columns by defining merge fields within table cells. Each row repeats based on the data collection.

Basic Table Syntax

Create a table structure in your Word template with the following pattern:

Column 1: <<foreach [product in products]>><<[product.productName]>>
Column 2: <<[product.manufactured]:"yyyy.MM.dd">>
Column 3: <<[product.price]>><</foreach>>

Template Structure:

  1. Create a table in Word with desired number of columns
  2. Place foreach loop in first cell
  3. Add merge fields in subsequent cells of the same row
  4. Close foreach loop in the last cell

Example: Product Inventory Table

Data Source (JSON):

{
"vendorName": "Instamart",
"products": [
{
"productName": "Laptops",
"price": 160000,
"manufactured": "25/07/2022"
},
{
"productName": "Keyboard",
"price": 10000,
"manufactured": "12/04/2022"
},
{
"productName": "Speakers",
"price": 25000,
"manufactured": "08/05/2022"
}
]
}

Generated Output:

Product NameManufacturedPrice
Laptops2022.07.25160000
Keyboard2022.04.1210000
Speakers2022.05.0825000

Table Calculations and Totals

Calculate aggregate values like sums, averages, and counts within your table structures using enumeration methods.

Sum Calculation

Add a total row to calculate the sum of numeric columns:

Column 1: <<foreach [product in products]>><<[product.productName]>>
Column 2: <<[product.manufactured]:"yyyy.MM.dd">>
Column 3: <<[product.price]>><</foreach>>
Column 1: Total
Column 2:
Column 3: $<<[products.Sum(c => c.price)]>>

Generated Output:

Product NameManufacturedPrice
Laptops2022.07.25160000
Keyboard2022.04.1210000
Speakers2022.05.0825000
Total$195000

Other Aggregate Functions

Average:

Average Price: $<<[products.Average(p => p.price)]:"F2">>

Count:

Total Products: <<[products.Count()]>>

Maximum:

Highest Price: $<<[products.Max(p => p.price)]>>

Minimum:

Lowest Price: $<<[products.Min(p => p.price)]>>

Single-Column Tables

Generate tables with a single column containing multiple lines of information per row. Use the -greedy switch to ensure each collection item occupies one row.

Single-Column Template Syntax

<<foreach [product in products]>>Product: <<[product.productName]>>, Manufactured On: <<[product.manufactured]:"yyyy.MM.dd">>, Product Price: $<<[product.price]>><</foreach -greedy>>

Key Point: The -greedy switch treats the entire content block as a single row, preventing unwanted row breaks.

Generated Output:

Product Details
Product: Laptops, Manufactured On: 2022.07.25, Product Price: $160000
Product: Keyboard, Manufactured On: 2022.04.12, Product Price: $10000
Product: Speakers, Manufactured On: 2022.05.08, Product Price: $25000

Advanced Table Examples

Example 1: Invoice Line Items Table

Template:

Item | Description | Qty | Unit Price | Total
<<foreach [item in lineItems]>><<[item.code]>> | <<[item.description]>> | <<[item.quantity]>> | $<<[item.unitPrice]:"F2">> | $<<[item.quantity * item.unitPrice]:"F2">><</foreach>>
| | | Subtotal: | $<<[lineItems.Sum(i => i.quantity * i.unitPrice)]:"F2">>

Example 2: Employee Directory Table

Template:

Name | Department | Email | Phone
<<foreach [emp in employees.OrderBy(e => e.lastName)]>><<[emp.firstName]>> <<[emp.lastName]>> | <<[emp.department]>> | <<[emp.email]>> | <<[emp.phone]>><</foreach>>
Total Employees: <<[employees.Count()]>>

Example 3: Sales Report Table

Template:

Month | Revenue | Expenses | Profit
<<foreach [month in salesData]>><<[month.name]>> | $<<[month.revenue]:"F2">> | $<<[month.expenses]:"F2">> | $<<[month.revenue - month.expenses]:"F2">><</foreach>>
Annual Total | $<<[salesData.Sum(m => m.revenue)]:"F2">> | $<<[salesData.Sum(m => m.expenses)]:"F2">> | $<<[salesData.Sum(m => m.revenue - m.expenses)]:"F2">>

Conditional Table Rows

Generate table rows conditionally based on data properties or business logic.

Filtered Rows

Template:

Product | Stock Status
<<foreach [product in products.Where(p => p.inStock == true)]>>
<<[product.name]>> | Available
<</foreach>>

Conditional Formatting

Template:

Employee | Status
<<foreach [emp in employees]>>
<<[emp.name]>> | <<if [emp.active]>>Active<<else>>Inactive<</if>>
<</foreach>>

Table Formatting Best Practices

Design Guidelines

  1. Header rows - Create clear, descriptive column headers
  2. Consistent alignment - Align numeric data right, text data left
  3. Appropriate widths - Set column widths based on expected content
  4. Formatting - Apply formatting (borders, shading) in the Word template
  5. Totals placement - Place aggregate calculations in appropriate summary rows

Data Preparation

  1. Clean data - Ensure data is properly formatted before template processing
  2. Handle nulls - Provide default values for null fields
  3. Limit rows - Consider pagination for very large datasets
  4. Sort data - Pre-sort data or use OrderBy in templates

Complex Table Structures

Multi-Level Grouping

Template:

Category | Product | Price
<<foreach [cat in categories]>>
<<[cat.name]>> | |
<<foreach [prod in cat.products]>>
| <<[prod.name]>> | $<<[prod.price]>>
<</foreach>>
| Category Total | $<<[cat.products.Sum(p => p.price)]>>
<</foreach>>

Tables with Conditional Sections

Template:

Item | Quantity | Price | Discount | Total
<<foreach [item in orderItems]>>
<<[item.name]>> | <<[item.qty]>> | $<<[item.price]>> | <<if [item.discount > 0]>><<[item.discount]>>%<<else>>-<</if>> | $<<[item.total]>>
<</foreach>>

Special Table Features

Greedy Switch Usage

The -greedy switch controls how content is distributed across table cells:

Without -greedy: Each property may create a new row With -greedy: Entire content block stays in one row

Example:

<<foreach [item in items]>>
<<[item.prop1]>>, <<[item.prop2]>>, <<[item.prop3]>>
<</foreach -greedy>>

Vertical Merging

For cells that should span multiple rows, set up cell merging in the Word template before adding merge fields.


Troubleshooting Table Generation

Common Issues and Solutions

Issue: Table rows not repeating correctly
Solution: Ensure foreach loop spans across all cells in the row

Issue: Unwanted extra rows
Solution: Use -greedy switch for single-row content

Issue: Incorrect calculations
Solution: Verify expression syntax and data types

Issue: Formatting lost after generation
Solution: Apply formatting to template cells, not just merge field syntax

Issue: Empty tables when data exists
Solution: Check property names match data source exactly


Complete Example: Sales Invoice

Template:

Invoice Date: <<[invoiceDate]:"MMMM dd, yyyy">>
Customer: <<[customerName]:caps>>

Item No. | Description | Qty | Unit Price | Amount
<<foreach [item in lineItems]>>
<<[item.itemNo]>> | <<[item.description]>> | <<[item.quantity]>> | $<<[item.unitPrice]:"F2">> | $<<[item.quantity * item.unitPrice]:"F2">>
<</foreach>>
| | | Subtotal: | $<<[lineItems.Sum(i => i.quantity * i.unitPrice)]:"F2">>
| | | Tax (10%): | $<<[lineItems.Sum(i => i.quantity * i.unitPrice) * 0.10]:"F2">>
| | | **Total:** | **$<<[lineItems.Sum(i => i.quantity * i.unitPrice) * 1.10]:"F2">>**

Table Design

Design your table structure in Word first with appropriate formatting, borders, and styling. Then add merge fields and foreach loops to the designed table for best results.