Design
Loop over array
Repeat any part of your document
COMMUNITY FEATURE
Available for:
Carbone Cloud
Carbone On-premise
Embedded Carbone JS
v2.0+
Overview
Carbone repeats any part of a document (rows, titles, pages...) from an array in your data.
Mark the pattern with two consecutive items: [i] on the first, [i+1] on the next. Carbone takes the [i] item as the example, automatically detects the block to repeat, outputs one copy per array element, and removes the [i+1] marker row before rendering.
An empty array renders nothing: both the [i] and [i+1] rows are removed.
Simple array
In this example, we want to loop over an array of cars. This is a vertical loop: Carbone repeats the pattern downward, adding one row per array item.
{
"cars" : [
{"brand" : "Toyota" , "id" : 1 },
{"brand" : "Hyundai", "id" : 2 },
{"brand" : "BMW" , "id" : 3 },
{"brand" : "Peugeot", "id" : 4 }
]
}
Carsid{d.cars[i].brand}{d.cars[i].id}{d.cars[i+1].brand}
CarsidToyota1Hyundai2BMW3Peugeot4
Only one [i+1] tag is enough to find the repetition pattern. It is not necessary to repeat the whole [i+1] part.
Get inspired by one of our real-life examples: Menu, Simple Planning or Best Manufacturer Awards
Nested arrays
Carbone manages nested arrays (unlimited depth). Here is an example where a whole portion of a document is repeated.
[
{
"brand": "Toyota",
"models": [{ "size": "Prius 4", "power": 125 }, { "size": "Prius 5", "power": 139 }]
},
{
"brand": "Kia",
"models": [{ "size": "EV4", "power": 450 }, { "size": "EV6", "power": 500 }]
}
]
{d[i].brand}Models{d[i].models[i].size} - {d[i].models[i].power}{d[i].models[i+1]}{d[i+1]}
ToyotaModelsPrius 4 - 125Prius 5 - 139KiaModelsEV4 - 450EV6 - 500
Notice that the whole first block is not repeated: only the closing title # {d[i+1]} is needed. This single [i+1] marker is enough for Carbone to detect where the outer loop, on the root array d, ends.
Get inspired by one of our real-life examples: Best Selling Vehicles Awards or Stock Inventory Spreadsheet
Horizontal loops (repeat columns)
A horizontal loop repeats columns instead of rows. Mark the [i] and [i+1] positions on two consecutive columns of the same row, and Carbone adds one column per array item, growing the table to the right. One difference with the vertical loop matters: it closes the whole block with a single [i+1], while a horizontal loop repeats within each row, so every marked row needs its own [i+1] end-marker (a bare {d.array[i+1]} is enough).
Example
Here we turn a list of products into columns, one column per product. The first column holds static labels, one per row. The loop fills the rest, adding one product column per array item as it grows to the right:
{
"products": [
{ "name": "Bike", "price": 200, "stock": 12, "category": "Outdoor" },
{ "name": "Chair", "price": 40, "stock": 30, "category": "Office" },
{ "name": "Lamp", "price": 25, "stock": 54, "category": "Home" }
]
}
Name{d.products[i].name}{d.products[i+1]}Price{d.products[i].price}{d.products[i+1]}Stock{d.products[i].stock}{d.products[i+1]}Category{d.products[i].category}{d.products[i+1]}
NameBikeChairLampPrice2004025Stock123054CategoryOutdoorOfficeHome
Get inspired by one of our real-life examples: Product Comparison Table or Sensor readings
Bi-directional loop
v4.8.0+
The bidirectional loop performs iterations in 2 directions, creating additional columns and rows.
There are a few restrictions:
- The JSON parent array must be used for rows, and the nested array must be used for columns. This limitation will be removed in Carbone v5.
- Officially supported in DOCX, HTML, MD templates. In addition, Word can automatically resize the table to fit the page width. Bidirectional loops with other template formats are still experimental. Please get in touch with us in the chat if necessary.
{
"titles" : [{ "name": "Kia" }, { "name": "Toyota" }, { "name": "Hopium" }],
"cars" : [
{ "models" : [ "EV3", "Prius 1", "Prototype" ] },
{ "models" : [ "EV4", "Prius 2", "" ] },
{ "models" : [ "EV6", "Prius 3", "" ] }
]
}
{d.titles[i].name}{d.titles[i+1].name}{d.cars[i].models[i]}{d.cars[i].models[i+1]}{d.cars[i+1].models[i]}
KiaToyotaHopiumEV3Prius 1PrototypeEV4Prius 2EV6Prius 3
Get inspired by one of our real-life examples: Store Inventory or Product Comparison Table
Access the loop iterator value
v4.0.0+
Access the iterator value when a list is printed in a document.
For example: {d[i].cars[i].other.wheels[i].tire.subObject:add(.i):add(..i):add(...i)}
The number of dots corresponds to the position of the i in the hierarchy:
...irefers to the index value ofwheels[i]..irefers to the index value ofcars[i].irefers to the index value ofd[i]
The number of dots is currently inverted. It should be ...i for d[i] and .i for wheels[i].
This is a known bug. However, many users rely on the current behavior, and fixing it would break some reports.
We plan to address this issue in the future while ensuring backward compatibility.
Get inspired by one of our real-life examples: Summary
Parallel loop
Iterate through two separate arrays at the same time using the same iterator variable.
As seen earlier, the iterator i can be used in formatters.
By combining it with relative path access, we can navigate back in the JSON hierarchy using two dots (..).
This allows us to print the content of another array, brands, using the same iterator as the cars array.
{
"cars" : [
{ "id" : 1 },
{ "id" : 2 },
{ "id" : 3 },
{ "id" : 4 }
],
"brands" : [
{ "name" : "Toyota" },
{ "name" : "Hyundai"},
{ "name" : "BMW" }
]
}
Carsid{d.cars[i].id}{d.cars[i].id:print(..brands[.i].name)}{d.cars[i+1].id}
Carsid1Toyota2Hyundai3BMW4
Array of string/number loop
v4.9.0+
When an array holds plain strings or numbers instead of objects, loop on the value itself with {d.colors[i]}, without a property name.
{
"colors": ["Red", "Green", "Blue"]
}
Colors{d.colors[i]}{d.colors[i+1]}
ColorsRedGreenBlue
Looped values accept formatters like any other tag, for example {d.colors[i]:upperCase}.