# Repeating Group

Repeats a component template for each API item.

URL: https://webrad.atentor.com/docs/repeating-group
Updated: 2026-11-07

WebRepeatingGroup · Containers · Visual · 2 events

## Quick start

Add **RepeatingGroup1** in the Designer. Use the example in a page method.

```ts
RepeatingGroup1.repeatingGroupConfig = {
  ...RepeatingGroup1.repeatingGroupConfig,
  gap: 12,
  rowHeightMode: 'dynamic',
  emptyMessage: 'No items',
};
await ApiClient1.execute('Load');
Message(RepeatingGroup1.rowCount);
```

CurrentRow is the third parameter of template child events. CurrentRow.value contains the item and CurrentRow.index its index.

- Configure the API operation and listPath in the editor; children form a template for each item.
- On each child, use **Current row** in the Inspector to bind a property to a field.
- Child events receive CurrentRow typed by the operation schema. Use this context to act on the correct item.
- Configure gap and fixed or dynamic height. rowCount and getRow(index) let you inspect mounted rows.

## More examples

Complete list configuration

```ts
const operation = ApiClient1.operations.find(item => item.name === 'Load');
if (!operation) throw new Error('Configure the Load operation in the Designer.');
RepeatingGroup1.repeatingGroupConfig = {
  schemaVersion: 1,
  apiClientId: ApiClient1.id,
  operationId: operation.id,
  listPath: '/data',
  rowHeightMode: 'dynamic',
  fixedRowHeight: 80,
  minRowHeight: 32,
  maxRowHeight: null,
  gap: 12,
  emptyMessage: 'No customers',
};
RepeatingGroup1.bindApiClient(ApiClient1);
await ApiClient1.execute('Load');
```

Interaction for a Button inside the template

```ts
import type { WebButton, WebRepeatingGroupCurrentRow } from '@webrad/runtime';
// This example’s Load schema contains items with id:number and name:string.
// The IDE generates the concrete signature; copy the body into your generated method.
class Example {
  public async OpenCustomer(
    sender: WebButton,
    event: Event,
    CurrentRow: WebRepeatingGroupCurrentRow<{ id: number; name: string }>,
  ): Promise<void> {
    Message(CurrentRow.value.name);
    console.log(CurrentRow.index, CurrentRow.value.id);
  }
}
```

## Inspector properties

Component options and defaults. Fields without runtime access are configured in the Inspector.

| Property / source | Type and options | Default | Runtime access |
| --- | --- | --- | --- |
| `name` — Name · Identity | `string` | `—` | name |
| `x` — Left · Size & position | `number` | `0` | x |
| `y` — Top · Size & position | `number` | `0` | y |
| `width` — Width · Size & position | `number` | `420` | width |
| `height` — Height · Size & position | `number` | `320` | height |
| `itemWidth` — Responsive width · Responsive size — Fit content grows the item to its widest rendered child and preserves child intrinsic widths; minimum and maximum width remain limits. | `enum` — `fixed` `stretch` `fit-content` | `"fixed"` | Inspector / configuration |
| `itemHeight` — Responsive height · Responsive size — Fit content grows the item to its lowest rendered child and preserves child intrinsic heights; minimum and maximum height remain limits. | `enum` — `fixed` `stretch` `fit-content` | `"fixed"` | Inspector / configuration |
| `itemMinWidth` — Minimum width · Responsive size | `number` | `0` | Inspector / configuration |
| `itemMaxWidth` — Maximum width · Responsive size | `number` | `null` | Inspector / configuration |
| `itemMinHeight` — Minimum height · Responsive size | `number` | `0` | Inspector / configuration |
| `itemMaxHeight` — Maximum height · Responsive size | `number` | `null` | Inspector / configuration |
| `itemGrow` — Grow · Responsive size | `number` | `0` | Inspector / configuration |
| `itemShrink` — Shrink · Responsive size — Allows fixed and stretch flow items to yield space. Fit-content keeps its intrinsic size so its children are not compressed. | `boolean` | `true` | Inspector / configuration |
| `itemAlignSelf` — Item alignment · Responsive size — Cross-axis alignment for this item in a row or column. Auto inherits the parent alignment; responsive cross-axis stretch retains its sizing behavior. | `enum` — `auto` `start` `center` `end` `stretch` | `"auto"` | Inspector / configuration |
| `itemHorizontalAnchor` — Horizontal anchor · Anchors & offsets | `enum` — `start` `center` `end` `stretch` | `"start"` | Inspector / configuration |
| `itemVerticalAnchor` — Vertical anchor · Anchors & offsets | `enum` — `start` `center` `end` `stretch` | `"start"` | Inspector / configuration |
| `itemLeft` — Left inset · Anchors & offsets | `number` | `0` | Inspector / configuration |
| `itemRight` — Right inset · Anchors & offsets | `number` | `0` | Inspector / configuration |
| `itemTop` — Top inset · Anchors & offsets | `number` | `0` | Inspector / configuration |
| `itemBottom` — Bottom inset · Anchors & offsets | `number` | `0` | Inspector / configuration |
| `margin` — Margin · Spacing — Outer spacing on all four sides, in pixels. Row and column layouts include this spacing between components. | `number` | `0` | margin |
| `marginTop` — Margin top · Spacing — Outer spacing on this side, in pixels. Overrides the shared Margin value. | `number` | `0` — Derived from saved properties | marginTop |
| `marginRight` — Margin right · Spacing — Outer spacing on this side, in pixels. Overrides the shared Margin value. | `number` | `0` — Derived from saved properties | marginRight |
| `marginBottom` — Margin bottom · Spacing — Outer spacing on this side, in pixels. Overrides the shared Margin value. | `number` | `0` — Derived from saved properties | marginBottom |
| `marginLeft` — Margin left · Spacing — Outer spacing on this side, in pixels. Overrides the shared Margin value. | `number` | `0` — Derived from saved properties | marginLeft |
| `visible` — Visible · Behavior | `boolean` | `true` | visible |
| `collapseWhenHidden` — Collapse when hidden · Behavior — Removes the component from the layout while it is not visible. | `boolean` | `true` | collapseWhenHidden |
| `enabled` — Enabled · Behavior | `boolean` | `true` | enabled |
| `containerMode` — Container layout · Children layout | `enum` — `fixed` `align-to-parent` `row` `column` | `"fixed"` | Inspector / configuration |
| `containerPaddingTop` — Padding top · Children layout | `number` | `0` | Inspector / configuration |
| `containerPaddingRight` — Padding right · Children layout | `number` | `0` | Inspector / configuration |
| `containerPaddingBottom` — Padding bottom · Children layout | `number` | `0` | Inspector / configuration |
| `containerPaddingLeft` — Padding left · Children layout | `number` | `0` | Inspector / configuration |
| `containerGap` — Gap · Children layout | `number` | `0` | Inspector / configuration |
| `containerWrap` — Wrap · Children layout | `boolean` | `false` | Inspector / configuration |
| `containerJustifyContent` — Justify content · Children layout | `enum` — `start` `center` `end` `space-between` `space-around` | `"start"` | Inspector / configuration |
| `containerAlignItems` — Default alignment · Children layout — Default cross-axis alignment for children. Each child can override it with Item alignment. | `enum` — `start` `center` `end` `stretch` | `"start"` | Inspector / configuration |
| `repeatingGroupConfig` — Data source and rows · Repeating Group — Choose the API response list and row sizing. Children form one responsive row template. | `repeating-group-config` — Editor: repeating-group-configurator | `{"schemaVersion":1,"apiClientId":null,"operationId":null,"listPath":"","rowHeightMode":"dynamic","fixedRowHeight":120,"minRowHeight":80,"maxRowHeight":null,"gap":8,"emptyMessage":"No data"}` | repeatingGroupConfig |
| `currentRowBindings` — Current row · Data — Bind writable visual values to fields of this repeated row. | `current-row-bindings` — Editor: current-row-bindings | `[]` | currentRowBindings |

## API in code

| Member | Signature | Access |
| --- | --- | --- |
| `repeatingGroupConfig` | `get repeatingGroupConfig(): WebRepeatingGroupConfiguration;` | Read and write |
| `rows` | `get rows(): readonly T[];` | Read and write |
| `rowCount` | `get rowCount(): number;` | Read-only |

### `getRow`

method

```ts
getRow(index: number): WebRepeatingGroupRow<T>;
```

Example

```ts
if (RepeatingGroup1.rowCount > 0) {
  const row = RepeatingGroup1.getRow(0);
  console.log(row.index, row.value);
}
```

### `getTemplateHost`

method

```ts
getTemplateHost(): HTMLElement;
```

The Designer uses one editable host without serializing sampled row data.

Example

```ts
RepeatingGroup1.getTemplateHost();
```

### `configureRowTemplate`

method

```ts
configureRowTemplate(renderer: WebRepeatingGroupRowRenderer): void;
```

Runtime renderer owns creation; authored code only supplies values.

Example

```ts
// Advanced API used by the renderer. In generated pages, edit children in the Designer.
const configure = RepeatingGroup1.configureRowTemplate.bind(RepeatingGroup1);
// configure takes WebRepeatingGroupRowRenderer; the renderer creates one instance per row.
console.log(configure);
```

### `bindApiClient`

method

```ts
bindApiClient(apiClient: WebApiClient | null): void;
```

Observes completed API results; it never executes an operation itself.

Example

```ts
RepeatingGroup1.bindApiClient(ApiClient1);
```

### `subscribeRows`

method

```ts
subscribeRows(listener: WebRepeatingGroupRowListener<T>): () => void;
```

Example

```ts
RepeatingGroup1.subscribeRows(rows => console.log(rows));
```

### `dispose`

method

```ts
dispose(): void;
```

Example

```ts
// Call only when disposing of an instance whose lifecycle you control.
RepeatingGroup1.dispose();
```

Inherited members (26)

| Member | Signature | Access |
| --- | --- | --- |
| `currentRowBindings` | `currentRowBindings: readonly WebCurrentRowBinding[];` | Read and write |
| `element` | `readonly element: TElement;` | Read-only |
| `id` | `readonly id: string;` | Read-only |
| `name` | `readonly name: string;` | Read-only |
| `visible` | `visible: boolean;` | Read and write |
| `collapseWhenHidden` | `collapseWhenHidden: boolean;` | Read and write |
| `enabled` | `enabled: boolean;` | Read and write |
| `x` | `x: number;` | Read and write |
| `y` | `y: number;` | Read and write |
| `width` | `width: number;` | Read and write |
| `height` | `height: number;` | Read and write |
| `margin` — Outer spacing on all four sides, in pixels. | `margin: number;` | Read and write |
| `marginTop` | `marginTop: number;` | Read and write |
| `marginRight` | `marginRight: number;` | Read and write |
| `marginBottom` | `marginBottom: number;` | Read and write |
| `marginLeft` | `marginLeft: number;` | Read and write |
| `alignSelf` | `alignSelf: RuntimeLayoutAlignSelf;` | Read and write |
| `tabIndex` | `tabIndex: number;` | Read and write |
| `backgroundColor` | `backgroundColor: string;` | Read and write |
| `color` | `color: string;` | Read and write |
| `borderColor` | `borderColor: string;` | Read and write |

### `focus`

method

```ts
focus(options?: FocusOptions): void;
```

### `show`

method

```ts
show(): void;
```

### `hide`

method

```ts
hide(): void;
```

### `bindEvent`

method

```ts
bindEvent(eventName: string, handler: WebComponentEventHandler<this> | null): () => void;
```

### `emit`

method

```ts
emit(eventName: string, detail?: unknown): boolean;
```

## Events

Link methods in **Interaction**. [How to use events](https://webrad.atentor.com/docs/interactions).

### OnClick

Standard event (Event).

Signature and example

```ts
import type { WebRepeatingGroup } from '@webrad/runtime';
// Copy this method into the page class and link it in Interaction.
class Example {
  public async RepeatingGroup1Click(
    sender: WebRepeatingGroup,
    event: Event,
  ): Promise<void> {
    console.log(sender.name, event.type);
  }
}
```

### OnDblClick

Standard event (Event).

Signature and example

```ts
import type { WebRepeatingGroup } from '@webrad/runtime';
// Copy this method into the page class and link it in Interaction.
class Example {
  public async RepeatingGroup1DblClick(
    sender: WebRepeatingGroup,
    event: Event,
  ): Promise<void> {
    console.log(sender.name, event.type);
  }
}
```
