apache > cocoon
 

Repeater widget

Concept

An fd:repeater widget is a widget that repeats a number of other widgets. It can be used to create e.g. tables, repeating subforms, etc.

Definition

<fd:repeater id="..." initial-size="..." min-size="..." max-size="..." state="...">
  <fd:label>...</fd:label>
  <fd:hint>...</fd:hint>
  <fd:help>...</fd:help>
  <fd:widgets>
    [...]
  </fd:widgets>
  <fd:validation>
    [...]
  </fd:validation>
  <fd:on-create>
    [...]
  </fd:on-create>
  <fd:on-repeater-modified>
    [...]
  </fd:on-repeater-modified>
  <fd:attributes>
    <fd:attribute name="..." value="..."/>
  </fd:attributes>
</fd:repeater>

The fd:widgets element should contain a number of other widgets to repeat. This can be any of type of widget: field, multivaluefied, booleanfield, or even repeater itself.

The optional initial-size attribute allows to specify how much rows should be initially present on the repeater. It mostly avoids to display a table with only table headers. Default value is zero.

The optional min-size and max-size attributes control the size of the repeater. A validation error is set on the repeater when these boundaries are violated.

The fd:on-repeater-modified element is used to specify a repeater listener. This listener will be notified of rows additions, removal and reordering. The RepeaterEvent instance (accessible with the event variable in a javascript listener) allows to know which action (see class RepeaterEventAction) is happening on which row. When  a row is being deleted or the entire repeater is being cleared, two events are thrown : the ROW_DELETING or ROWS_CLEARING before the action actually takes place, and the ROW_DELETED or ROWS_CLEARED after the row has actually been deleted or the repeater has actually been cleared.

For a description of the other elements, see the field widget.

Template

Before Cocoon 2.1.8

The following elements are available for formatting a repeater in a template:

  • ft:repeater-widget: the content of this element is a template that will be executed for each row in the repeater
  • ft:repeater-widget-label: this element inserts the label of a widget contained by the repeater (to be used outside of ft:repeater-widget)
  • ft:repeater-size: inserts an element <fi:repeater-size id="..." size="..."/> containing the size (number of rows) of the repeater. This element is only needed when the form model is not stored in the server (thus when operating stateless). In that case the size of the repeater must be communicated on each round-trip.

An example that formats a repeater with ID "myrepeater", having two child widgets with IDs "field1" and "field2",  as a table:

<table>
  <tbody>
    <tr>
      <th><ft:repeater-widget-label id="myrepeater" widget-id="field1"/></th>
      <th><ft:repeater-widget-label id="myrepeater" widget-id="field2"/></th>
    </tr>
    <ft:repeater-widget id="myrepeater">
      <tr>
        <td><ft:widget id="field1"/></td>
        <td><ft:widget id="field2"/></td>
      </tr>
    </ft:repeater-widget>
  </tbody>
</table>

From Cocoon 2.1.8

Cocoon 2.1.8 introduced a slightly extended manner to format repeaters, which is required when using the new Ajax features. Instead of one ft:repeater-widget element, it uses two elements:

  • ft:repeater: encloses the entire formatted repeater
  • ft:repeater-rows: encloses the repeating part

Below is the same example as above using the new syntax. In addition, it illustrates the availability of a "repeaterLoop" variable inside the ft:repeater-rows element.

<ft:repeater id="myrepeater">
  <table>
    <tbody>
      <tr>
        <th><ft:repeater-widget-label widget-id="field1"/></th>
        <th><ft:repeater-widget-label widget-id="field2"/></th>
      </tr>
      <ft:repeater-rows>
        <tr class="forms-row-${repeaterLoop.index % 2}">
          <td><ft:widget id="field1"/></td>
          <td><ft:widget id="field2"/></td>
        </tr>
      </ft:repeater-rows>
    </tbody>
  </table>
</ft:repeater>

Tips

When using JXTemplate, it is possible to test if a repeater is empty and show something else in that case. For example:

<jx:choose>
  <jx:when test="${widget.getChild('myrepeater').getSize() == 0}">
    No items yet.
  </jx:when>
  <jx:otherwise>
   [... normal repeater formatting here ...]
  </jx:otherwise>
</jx:choose>