Skip to content

Repeater

WxRepeater is a field whose value is a list of records: offices with a city and an address, questions with an answer, sliders with a picture and a link. One set of fields, repeated, in an order that is part of the answer.

A record per row, named by one of its own fields
  • Office
  • Warehouse
2 offices, in this order.
Two fields and nothing else — no headers, no folding

Usage

vue
<script setup lang="ts">
import { ref } from 'vue'
import { WxFormItem, WxInput, WxRepeater } from '@webx-ui/core'

interface Office {
  city: string
  address: string
}

const offices = ref<Office[]>([{ city: 'Kyiv', address: 'Khreshchatyk 1' }])

const newOffice = (): Office => ({ city: '', address: '' })
</script>

<template>
  <wx-repeater v-model="offices" :new-item="newOffice" item-label="city" add-label="Add an office">
    <template #default="{ item, update }">
      <wx-form-item label="City">
        <wx-input :model-value="item.city" @update:model-value="update({ city: $event })" />
      </wx-form-item>

      <wx-form-item label="Address">
        <wx-input :model-value="item.address" @update:model-value="update({ address: $event })" />
      </wx-form-item>
    </template>
  </wx-repeater>
</template>

v-model is the list itself, in the order it is shown — saving it is saving the array.

Writing a row

The slot is given item, its index, and update: a patch of the row, applied to a copy of it in a copy of the list. Nothing the repeater hands out is ever mutated, so a parent that keeps the model in a store, a history or a readonly is safe.

vue
<template #default="{ item, update }">
  <wx-input :model-value="item.title" @update:model-value="update({ title: $event })" />
</template>

v-model="item.title" works too when the model is a local ref — it writes through the object in the array — but it is a mutation, and it is the one form that will not survive a frozen model.

What a row is called

itemLabel is a key of the item or a function of it, and it names the row twice: in the header above its fields, and to a screen reader holding the grip. Without one a row is numbered.

A header appears when there is something to put in it — an itemLabel, or collapsible. Two fields and no title need neither, and the demo's second repeater draws no headers at all.

Folding

collapsible folds a row to its header, which is what keeps a repeater of eight-field records readable. collapsed starts the rows that were already there folded; a row somebody has just added always opens, because it is the one they are about to fill in.

Folding is remembered per row rather than per position: removing the row above a folded one, or dragging it elsewhere, leaves it folded.

Limits

min and max bound the list: at max the add button is disabled, at min every remove button is. Neither fills the list up to min on its own — a repeater shows the model it was given.

Order

Rows are dragged by the grip, or moved with a keyboard: tab to the grip, space to pick the row up, the arrows to move it, space to drop it. It is WxSortableList underneath, and the move event is the same one. sortable: false takes the grip away for a list whose order means nothing.

Inside a screen

A screen described as JSON has this as wx-repeater, the one type with a nested model: the node's children are the fields of one row, and a name inside it is a key of the item.

Props

PropTypeDefault
modelValueT[][]
titlestring
itemLabelstring | ((item: T, i: number) => string)
newItem() => T() => ({})
addLabelstring'Add'
removeLabelstring'Remove'
collapsiblebooleanfalse
collapsedbooleanfalse
minnumber0
maxnumber
sortablebooleantrue
disabledbooleanfalse
emptyTextstring'Nothing here yet'
size'sm' | 'md''md'
plainbooleanfalse
ariaLabelstring

Slots

SlotPayloadWhat it is
default{ item, index, update }The fields of one row.
headerReplaces the title.
extraThe end of the heading.
actions{ item, index }Row actions, before the remove one.
emptyShown in place of an empty repeater.

Events

EventPayloadWhen
add(item, index)A row was appended.
remove(item, index)A row was dropped.
moveSortableMove<T>A row changed position.

Released under the MIT License.