npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 name values, 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()
  • duplicate from 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 $itempath is entries[0] then $parentpath is entries
  • if $itempath is entries[0][blocks][1] then $parentpath is entries[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 $formindex as 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:

  • blocks builds a nested array
  • seo_fields writes 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

  • name is required on every repeater
  • paths are built from repeater name values, not from component ids
  • use parent repeater actions directly through its id
  • use child repeater actions through $repeat inside the current row
  • parent repeaters should have an id if you want to call them directly
  • child repeaters do not need an id when they are discovered by name
  • $value represents the current row data scope
  • $itempath is the full path to the current row
  • $parentpath is 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 name for each repeater collection name
  • use $value to access current row data
  • use dmx-bind:name for 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"
}