Schema
Data Binding
Understand how data flows into bands and components through binding, iteration, and nested property access.
Overview
Data binding connects your report schema to the data passed at render time. It controls which array a detail band iterates over, how each element is exposed to components, and how nested properties are accessed.
How it works
When you call renderReport(schema, data), the data object becomes the root context for expression evaluation. Every {{...}} expression in your components resolves against this context.
const data = {
title: 'Sales Report',
customer: { name: 'Acme Corp', city: 'San Francisco' },
items: [
{ name: 'Widget', price: 29.99 },
{ name: 'Gadget', price: 49.99 },
],
}
With this data:
{{title}}resolves to"Sales Report"{{customer.name}}resolves to"Acme Corp"{{customer.city}}resolves to"San Francisco"
Detail band iteration
Detail bands require a dataBinding property that references an array in the data:
{
type: 'detail',
height: 28,
dataBinding: 'items',
components: [...]
}
The engine iterates over the array and renders the band once per element. During each iteration, the current element is available as an iterator variable.
Automatic iterator naming
The engine derives the iterator name by removing the trailing “s” from the array name:
dataBinding value | Iterator variable | How you access it |
|---|---|---|
items | item | {{item.name}} |
products | product | {{product.price}} |
employees | employee | {{employee.department}} |
orders | order | {{order.total}} |
This convention works well for standard English plurals.
Custom iteratorName
When automatic naming does not produce a useful variable name, set iteratorName explicitly:
{
type: 'detail',
height: 28,
dataBinding: 'entries',
iteratorName: 'entry',
components: [
{
type: 'text',
position: { x: 0, y: 4, width: 200, height: 20 },
content: '{{entry.label}}',
fontSize: 12,
},
],
}
Common cases where custom naming helps:
dataBinding | Auto-derived | Better iteratorName |
|---|---|---|
entries | entrie | entry |
data | dat | row |
people | peopl | person |
addresses | addresse | address |
Nested property access
You can access deeply nested properties using dot notation in both top-level and iterator contexts:
{{company.address.street}}
{{item.metadata.category.name}}
The engine traverses the object graph following each segment. If any intermediate property is undefined or null, the expression resolves to an empty string.
Combining contexts
Inside a detail band, both the iterator variable and the top-level data context are available. Iterator variables take precedence when names collide:
const data = {
currency: 'USD',
taxRate: 0.08,
items: [
{ name: 'Widget', price: 29.99 },
],
}
In this detail band:
{{item.name}}— from the iterator{{currency}}— from the top-level data{{formatCurrency(item.price * (1 + taxRate), currency)}}— mixed
Example: nested data
const data = {
company: {
name: 'Acme Corp',
contact: {
email: 'info@acme.com',
phone: '+1-555-0100',
},
},
orders: [
{
id: 'ORD-001',
customer: { name: 'Jane Smith' },
items: [
{ product: 'Widget', qty: 2 },
],
},
],
}
Schema expressions:
{{company.name}} → Acme Corp
{{company.contact.email}} → info@acme.com
{{order.id}} → ORD-001 (in detail band)
{{order.customer.name}} → Jane Smith (in detail band)
Next steps
- Bands — band types and data binding configuration
- Expressions — expression syntax and built-in functions
- Render API — pass data when rendering via the API