CxJS

Repeater

import { Repeater } from 'cx/widgets'; Copied

Repeater renders its children for each record in a collection. Use recordAlias to specify an accessor for accessing record data within the repeater.

Example

<div class="flex flex-col gap-4" controller={PageController}>
  <div class="flex flex-col gap-2">
    <Repeater records={m.items} recordAlias={m.$record}>
      <div class="flex items-center gap-2">
        <Checkbox value={m.$record.checked} text={m.$record.text} />
        <Button
          icon="close"
          mod="hollow"
          onClick={(e, { store }) => {
            store.delete(m.$record)
          }}
        />
      </div>
    </Repeater>
  </div>
  <div class="flex items-center gap-4">
    <div class="text-sm text-muted-foreground">
      Completed:{" "}
      <span
        text={expr(
          m.items,
          (items: Item[]) => items.filter((a) => a.checked).length,
        )}
      />{" "}
      of <span text={m.items.length} /> tasks
    </div>
    <Button
      onClick={(e, ins) => {
        ins.getControllerByType(PageController).reset()
      }}
    >
      Reset
    </Button>
  </div>
</div>
Completed: 1 of 3 tasks

Typed Model

Add $record to your model interface to get type-safe access to record data:

interface PageModel {
  items: Item[];
  $record: Item;
}

const m = createModel<PageModel>();

Then use recordAlias={m.$record} to bind the record accessor:

<Repeater records={m.items} recordAlias={m.$record}>
  <Checkbox value={m.$record.checked} text={m.$record.text} />
</Repeater>

Accessing the Record Store

Event handlers like onClick receive an instance object as the second argument. This instance contains a store that provides access to the record-specific data view. Use this to manipulate individual records:

<Button
  onClick={(e, { store }) => {
    store.delete(m.$record);
  }}
/>

The store.delete(m.$record) call removes the current record from the parent array.

Sorting and Filtering

Use sortField and sortDirection for sorting. For filtering, use filterParams with onCreateFilter:

<div class="flex flex-col gap-4" controller={PageController}>
  <TextField value={m.search} placeholder="Filter by name..." />
  <Repeater
    records={m.products}
    recordAlias={m.$record}
    sortField="name"
    sortDirection="ASC"
    filterParams={{ search: m.search }}
    onCreateFilter={(params) => {
      let predicate = getSearchQueryPredicate(params.search)
      return (item: Product) => predicate(item.name)
    }}
  >
    <div class="text-sm">
      <HighlightedSearchText text={m.$record.name} query={m.search} />
      <span text={expr(m.$record.price, (price) => ` - $${price}`)} />
    </div>
  </Repeater>
</div>
Apple - $0.9
Banana - $1.2
Grapes - $2.8
Mango - $2.3
Orange - $1.5
Pineapple - $3.5
Strawberry - $4
Watermelon - $5

Nested Repeaters

For nested repeaters, define separate record aliases in your model:

<div class="flex flex-col gap-4" controller={PageController}>
  <Repeater records={m.accounts} recordAlias={m.$account}>
    <div class="border rounded p-3">
      <div class="font-medium mb-2 leading-none" text={m.$account.name} />
      <Repeater records={m.$account.transactions} recordAlias={m.$transaction}>
        <div class="flex justify-between text-sm py-1 border-b last:border-b-0">
          <span text={m.$transaction.description} />
          <span text={m.$transaction.amount} />
        </div>
      </Repeater>
    </div>
  </Repeater>
</div>
Checking
Groceries-85.5
Salary3500
Electric bill-120
Savings
Transfer in500
Interest12.5

Configuration

PropertyTypeDescription
recordsProp<any[]>An array of records to be displayed
recordAliasAccessorChainAlias used to expose record data. Defaults to $record.
indexAliasAccessorChainAlias used to expose record index. Defaults to $index.
sortFieldStringPropA binding used to store the name of the field used for sorting the collection. Available only if sorters are not used.
sortDirectionProp<"ASC" | "DESC">A binding used to store the sort direction. Available only if sorters are not used. Possible values are "ASC" and "DESC". Defaults to "ASC".
sortersSortersPropA binding used to store the sorting order list. This should be an array of objects with field and direction properties (equivalent to sortField and sortDirection).
sortOptionsobjectOptions for data sorting. See Intl.Collator options for more info.
filterParamsStructuredPropParameters that affect filtering
onCreateFilterfunctionCallback to create a filter function for given filter params
onTrackMappedRecordsfunctionCallback function to track and retrieve displayed records. Accepts new records as a first argument. If onCreateFilter is defined, filtered records can be retrieved using this callback.
keyFieldstringField used to get the unique identifier. Improves performance on sort operations.
cachedbooleanSet to true to enable caching for improved performance on large datasets