@freeseller/wappler-nested-form-repeat
v0.5.0
Published
> This instruction and the examples below were generated with the help of AI. > They should be treated as a starting point, not as a complete specification. > To fully unlock the component potential, it is important to understand its logic and experiment
Downloads
389
Readme
@freeseller/wappler-nested-form-repeat
This instruction and the examples below were generated with the help of AI. They should be treated as a starting point, not as a complete specification. To fully unlock the component potential, it is important to understand its logic and experiment with it in real Wappler forms and nested structures.
The author already uses this component to build a dynamic article constructor and continues to improve and evolve it.
Nested Form Repeat for Wappler.
This component is based on the standard Form Repeat component, but is adapted for nested form structures.
Main differences from standard Form Repeat
- built on top of the standard Wappler Form Repeat logic
- supports nested repeaters
- parent/child paths are built from the component
namevalues, not from component ids - field names are not auto-generated like in the standard Form Repeat
- field names must be defined explicitly, usually with
dmx-bind:name - this makes the component more flexible for nested arrays and nested objects
- uses renamed actions:
nfrAdd(data)nfrAddChild(name, parentIndex, data)nfrRemove(index)nfrMove(oldIndex, newIndex)nfrMoveToStart(index)nfrMoveToEnd(index)nfrMoveBefore(index)nfrMoveAfter(index)nfrReset()
duplicatefrom the original component is not exposed as part of the intended public workflow- parent repeater should have an id when you want to call it directly
- child repeaters do not need an id when they are controlled through
$repeat
Core concepts
name is required
Each repeater must have a name.
The component uses name values to build nested paths.
Examples:
- parent repeater
name="entries" - child repeater
name="blocks"
This leads to payload paths like:
entries[0]entries[0][blocks][0]
id is only needed for direct parent actions
The parent repeater usually has an id so you can call actions directly:
<div is="dmx-nested-form-repeat"
id="entries_repeat"
name="entries"
dmx-bind:items="server_data.entries">
</div>Then you can call:
<button dmx-on:click="entries_repeat.nfrAdd()">Add row</button>
<button dmx-on:click="entries_repeat.nfrReset()">Reset</button>Child repeaters do not need an id when they are accessed through $repeat.
$value
$value is the data scope of the current row.
Examples:
$value.title$value.blocks$value.meta.code
$itempath
$itempath is the full path to the current row.
Examples:
entries[0]entries[0][blocks][1]
$parentpath
$parentpath is the path without the current row index.
Examples:
- if
$itempathisentries[0]then$parentpathisentries - if
$itempathisentries[0][blocks][1]then$parentpathisentries[0][blocks]
Important difference from standard Form Repeat
The standard Form Repeat automatically rewrites field names from static template fields.
This component is more flexible:
- you define field names yourself
- usually with
dmx-bind:name - this allows arrays and objects to be mixed in nested structures
So instead of relying on automatic name generation, you write the exact structure you want.
How actions are called
Parent level
Use the parent component id directly.
<button dmx-on:click="entries_repeat.nfrAdd()">Add parent row</button>
<button dmx-on:click="entries_repeat.nfrAdd({title: 'New entry'})">Add parent row with data</button>
<button dmx-on:click="entries_repeat.nfrReset()">Reset</button>Nested level
Inside a row, use $repeat.
Remove current row:
<button dmx-on:click="$repeat.nfrRemove($formindex)">Remove row</button>Add a child row into nested repeater blocks of the current parent row:
<button dmx-on:click="$repeat.nfrAddChild('blocks', $formindex, {type: 'text'})">
Add text block
</button>This means:
- use current row context
- find child repeater with
name="blocks" - use
$formindexas the parent row index - insert the provided data into the new child item
Example 1: Nested array structure
Markup
<div is="dmx-nested-form-repeat"
id="entries_repeat"
name="entries"
dmx-bind:items="server_data.entries">
<div>
<input dmx-bind:name="$itempath + '[record_id]'" type="hidden" dmx-bind:value="'entry_' + $formindex">
<input dmx-bind:name="$itempath + '[title]'" type="text" dmx-bind:value="$value.title">
<button type="button" dmx-on:click="$repeat.nfrAddChild('blocks', $formindex, {type: 'text'})">
Add text block
</button>
<div is="dmx-nested-form-repeat"
name="blocks"
dmx-bind:items="$value.blocks">
<div>
<input dmx-bind:name="$itempath + '[type]'" type="hidden" value="text">
<textarea dmx-bind:name="$itempath + '[content]'" dmx-bind:value="$value.content"></textarea>
</div>
</div>
</div>
</div>
<button dmx-on:click="entries_repeat.nfrAdd({title: 'New entry'})">
Add parent row
</button>Example server data
{
"entries": [
{
"record_id": "entry_0",
"title": "First entry",
"blocks": [
{
"type": "text",
"content": "Hello"
}
]
}
]
}Example payload sent to the server
{
"entries": [
{
"record_id": "entry_0",
"title": "First entry",
"blocks": [
{
"type": "text",
"content": "Hello"
}
]
},
{
"record_id": "entry_1",
"title": "New entry"
}
]
}Example 2: Nested object structure with $parentpath
Use $parentpath when a field should be written under the parent object path instead of the current array item path.
In this example the parent row contains two child repeaters:
blocksbuilds a nested arrayseo_fieldswrites values into a nested object
Markup
<div is="dmx-nested-form-repeat"
id="articles_repeat"
name="articles"
dmx-bind:items="server_data.articles">
<div>
<input dmx-bind:name="$itempath + '[title]'" type="text" dmx-bind:value="$value.title">
<div is="dmx-nested-form-repeat"
name="blocks"
dmx-bind:items="$value.blocks">
<div>
<input dmx-bind:name="$itempath + '[type]'" type="hidden" value="text">
<textarea dmx-bind:name="$itempath + '[content]'" dmx-bind:value="$value.content"></textarea>
</div>
</div>
<div is="dmx-nested-form-repeat"
name="seo_fields"
dmx-bind:items="$value.seo_fields">
<div>
<input dmx-bind:name="$itempath + '[field]'" type="hidden" dmx-bind:value="$value.field">
<input dmx-bind:name="$parentpath + '[seo][' + $value.field + ']'"
type="text"
dmx-bind:value="$value.value">
</div>
</div>
</div>
</div>Example server data
{
"articles": [
{
"title": "Article A",
"blocks": [
{
"type": "text",
"content": "Intro"
}
],
"seo_fields": [
{ "field": "title", "value": "SEO Title" },
{ "field": "description", "value": "SEO Description" },
{ "field": "keywords", "value": "seo, example" }
]
}
]
}Example payload sent to the server
{
"articles": [
{
"title": "Article A",
"blocks": [
{
"type": "text",
"content": "Intro"
}
],
"seo_fields": [
{ "field": "title", "value": "SEO Title" },
{ "field": "description", "value": "SEO Description" },
{ "field": "keywords", "value": "seo, example" }
],
"seo": {
"title": "SEO Title",
"description": "SEO Description",
"keywords": "seo, example"
}
}
]
}This is useful when you need both:
- row-based nested editing
- direct object mapping under the parent item
Adding data programmatically
Add parent item with data
<button dmx-on:click="entries_repeat.nfrAdd({
record_id: 'entry_new',
title: 'Created from action'
})">
Add parent with data
</button>Add child item with data
<button dmx-on:click="$repeat.nfrAddChild('blocks', $formindex, {
type: 'text',
content: 'Inserted block'
})">
Add child with data
</button>Notes
nameis required on every repeater- paths are built from repeater
namevalues, not from component ids - use parent repeater actions directly through its
id - use child repeater actions through
$repeatinside the current row - parent repeaters should have an
idif you want to call them directly - child repeaters do not need an
idwhen they are discovered byname $valuerepresents the current row data scope$itempathis the full path to the current row$parentpathis the path to the parent container without the current row index- field names should be defined explicitly, usually with
dmx-bind:name
Recommended pattern
- use
namefor each repeater collection name - use
$valueto access current row data - use
dmx-bind:namefor fields so you control the exact payload structure - use
$repeat.nfrRemove($formindex)inside row context - use the parent component id for top-level add/reset actions
Package
{
"name": "@freeseller/wappler-nested-form-repeat",
"version": "0.5.0"
}