Repeater Field Type
Renders a custom TrRepeater Component inside the block
The type we would use inside the schema’s field_meta property to render this field is “repeater”: "type": "repeater"
If you haven’t already, we suggest you read the “model.json file” and “Field Types” pages before continuing.
The repeater field type can be used to repeat (to create an array of) either one or more Fields (Field Types).
It can also have another repeater element as a Field Type that’s been repeated, with a limitation that the inner (repeated) repeater can’t have any more nested repeaters. So the maximum level of nesting is 2.
That inner repeater can, of course, wrap one or more Field Types of any type other than the repeater type. Here are a few example configurations/screenshots of simple and a bit complex repeater configurations (schemas).
Apart from being used to repeat elements, this field can be used as a “pseudo group” which we will explain later.
Minimum Schema needed to create the field (example)
"titles": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Titles",
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
}
}
},
"default": []
}
This snippet of code will generate a repeater control. The field name will be “titles”, its label will be “Titles” and it will have an empty array as a default value. This example only repeats one Text Field type (Title), but, as mentioned above, it can repeat more Field Types.
As we can see in the schema above, the field_meta
property on the repeater Field Type contains a nested subfields
property. This is the place where we would place all the nested fields that we want to use. This is a required property.
What it would look like inside the block in the editor.
As we can see from the GIF above, the simple Schema we defined for the repeater field inside the model.json file generates the wrapper repeater component. The repeater component by default allows us to add/remove, reorder, and collapse/un-collapse repeated items.
Rendering field’s data on the front-end:
<div n:if="!empty($titles)">
<h2
n:foreach="$titles as $item"
n:ifcontent
>
{$item['title']['text']}
</h2>
</div>
Repeater field with multiple sub-fields (example)
"fields": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Fields",
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
},
"cta": {
"type": "object",
"field_meta": {
"type": "cta",
"label": "CTA"
},
"default": {
"title": "",
"url": "",
"target": false
}
},
"image": {
"type": "object",
"field_meta": {
"type": "image",
"label": "Image"
},
"default": {
"src": "",
"id": null
}
}
}
},
"default": []
}
}
<div n:if="!empty($fields)">
<div
n:foreach="$fields as $item"
>
<h2 n:ifcontent>{$item['title']['text']}</h2>
{tr_a($item['cta'], "btn btn--brand")}
{if isset($item['image']) && $item['image']['src']}
{tr_get_media($item['image'])}
{/if}
</div>
</div>
Repeater field with a nested repeater sub-field (example)
"fields": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Fields",
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
},
"cta": {
"type": "object",
"field_meta": {
"type": "cta",
"label": "CTA"
},
"default": {
"title": "",
"url": "",
"target": false
}
},
"nested_repeater_items": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Nested Repeater Items",
"subfields": {
"nested_title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Nested Title"
},
"default": {
"text": ""
}
}
}
},
"default": []
}
}
},
"default": []
}
<div
n:if="!empty($fields)"
n:foreach="$fields as $item"
>
<h2 n:ifcontent>{$item['title']['text']}</h2>
{tr_a($item['cta'], "btn btn--brand")}
<h3
n:foreach="$item['nested_repeater_items'] as $sub_item"
n:ifcontent
>
{$sub_item['nested_title']['text']}
</h3>
</div>
field_meta properties
Besides the optional properties help
(explained on Field Types page), and col
(explained on model.json page), this field type has a few more field_meta required and optional properties.
Those properties are:
subfields
– requiredgrid
– optionalgrid_gap
– optionaldisable_reordering
– optionalrepeater__item__label
– optionalrepeater__item__help
– optionalmax_rep
– optionalmin_rep
– optional
subfields
subfields property is an object where we would place all the nested fields that we want to use. This is a required property.
grid
Similar to how we are using the grid and col properties on the root level Fields, we can use the grid optional property on the repeater field itself. The only difference is that the grid for the root level fields is defined inside the block_meta
property of the main model.json
file. Besides that, the repeater’s grid property accepts an integer as a value as opposed to the root level grid that accepts a string of 3 predefined options, as described on the model.json page.
By default, and, if this property is not defined, repeater items will be stacked vertically. By using this property, we can change that. Here’s a quick example (We’ll use the first example schema from the top of this page).
...
"titles": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Titles",
"grid": 3,
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
}
}
},
"default": []
}
...
grid_gap
Vertical space between items (cells). If grid property is used, it also affects horizontal spacing. It accepts integer as a value. Default is 10 if not defined.
...
"grid_gap": 20,
...
disable_reordering
By default, repeater items can be reordered by clicking on the arrow left/right icons that are visible in the header of each repeater item. This can be disabled by defining the disable_reordering property and setting its value to true. Doing this will remove the arrow icons and disable this feature.
...
"disable_reordering": true,
...
repeater__item__label
From the screenshot above we can see that the default label for each repeater item (group wrapping the actual field/s) is “Item”. We can overwrite that via the repeater__item__label
property. In this example, we have a repeater where each repeater item has only the title field. If we do this…
...
"repeater__item__label": "Title",
...
… now, instead of the generic “Item”, the labels for each repeater item as well as for the Add button are replaced with “Title”.
repeater__item__help
...
"repeater__item__help": "This is a help text tooltip defined for each repeater item.",
...
This optional property allows us to define a tooltip that will show for each repeater item.
max_rep
Optional property. By default, the maximum number of items that can be added to a repeater field is set to 100.
This can be overwriten by defining the max_rep
property and setting its value to an integer.
...
"max_rep": 5,
...
Notice, how, once we get to the maximum number of allowed repeater items, the “Add” button disappears.
min_rep
Controls the minimum number of items that the repeater can have. By default, this is 0.
...
"min_rep": 2,
...
This property is a bit different from the max_rep one because it expects a bit more configuration in order for the repeater not to break.
Up until now, we’ve been setting the repeater’s default
property to an empty array []
. In order for min_rep to work, we would need to change that, and let’s say that our titles repeater needs a minimum of 2 items in order for it to work on the front-end; This is how we would write the Schema.
...
"titles": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Titles",
"min_rep": 2,
"max_rep": 4,
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
}
}
},
"default": [
{
"title": {
"text": ""
}
},
{
"title": {
"text": ""
}
}
]
}
...
This example only has a Title subfield that’s of the text type. For each of the repeater items (taking into account the min_rep), we need to manually populate the repeater’s default array. In the case where each repeater item contains multiple subfields, we would need to add them inside the same object where the title is written (for each repeater item). At a minimum, we need to do this min_rep number of times, but, if we want, we can prepopulate more than 2 (in this example); We can prepopulate all the repeater items. In this case, we’ve also set the max_rep property to 4, so that’s also the maximum count of objects we can prepopulate.
Repeater as a “Pseudo Group”
Earlier on this page, we’ve said that we can use the repeater field as a “pseudo group”. We can do that with the combination of the min_rep
and max_rep
properties.
Say we know we have 3 columns on the front-end (or 3 cards). The number can’t vary. It will always be 3. Each of the cards will have a title, text, and link fields. This is how we would achieve this.
"cards": {
"type": "array",
"field_meta": {
"type": "repeater",
"label": "Cards",
"repeater__item__label": "Card",
"min_rep": 3,
"max_rep": 3,
"grid": 3,
"subfields": {
"title": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Title"
},
"default": {
"text": ""
}
},
"text": {
"type": "object",
"field_meta": {
"type": "text",
"label": "Text",
"max_chars": 100
},
"default": {
"text": ""
}
},
"cta": {
"type": "object",
"field_meta": {
"type": "cta",
"label": "CTA",
"help": "Optional (Leave url field empty if you don't want to show the button)"
},
"default": {
"title": "",
"url": "",
"target": false
}
}
}
},
"default": [
{
"title": {
"text": ""
},
"text": {
"text": ""
},
"cta": {
"title": "",
"url": "",
"target": false
}
},
{
"title": {
"text": ""
},
"text": {
"text": ""
},
"cta": {
"title": "",
"url": "",
"target": false
}
},
{
"title": {
"text": ""
},
"text": {
"text": ""
},
"cta": {
"title": "",
"url": "",
"target": false
}
}
]
}
...
This Schema will generate this UI.
Optionally, we could also use the "disable_reordering": true
, to lock the cards.