Skip to content

Dynamic Computation

Available from version 2.26.0. Configure a form element to automatically compute the sum (or other transformation) of values from repeatable elements, updating in real time as the user fills in the form.

The pattern: emitter and subscriber

Dynamic computation uses an event system with two roles:

  • Emitter — a source element (inside a repeatable section) that publishes its value when it changes
  • Subscriber — a target element that receives the emitted values and applies a transformation to compute a result

Configuring the emitter

The emitter is inside a repeatable section. Add computationConfig to the element that should be summed:

{
  "key": "retentionValue",
  "label": "Retention Value",
  "type": "numeric-input",
  "computationConfig": {
    "emitter": {
      "eventName": "retention-total-event"
    }
  }
}

The eventName must be unique across the entire application.

Configuring the subscriber

The subscriber is the target field that displays the computed result. It should be non-editable:

{
  "key": "totalRetentionValue",
  "label": "Total Retention",
  "type": "numeric-input",
  "modifierClass": "non-editable",
  "computationConfig": {
    "subscriber": {
      "eventName": "retention-total-event",
      "transformExpression": "model?.reduce((sum, el) => sum + Number(el.retentionValue), 0) || 0"
    }
  }
}

The transformExpression is a JavaScript expression. model contains the array of emitted values (one per repeatable row). The expression above sums the retentionValue field from each row.

Alternative: computationSourceFormPath

Use computationSourceFormPath instead of eventName when multiple instances of the same screen exist (e.g. multiple products, each with its own retention repeatable). This binds to a specific form path without event emission, avoiding cross-instance interference:

{
  "computationConfig": {
    "subscriber": {
      "computationSourceFormPath": "productCoverDetail.data.retentions",
      "transformExpression": "model?.reduce((sum, el) => sum + Number(el.retentionValue), 0) || 0"
    }
  }
}

Tips

  • Event names must be globally unique. Use a descriptive name that includes the business class or action name to avoid collisions.
  • The subscriber field should always be modifierClass: "non-editable" — it is a computed field, not a user input.
  • The transformExpression runs in the browser. Standard JavaScript array methods (reduce, map, filter) are available.
  • If model is null or empty (no rows added yet), the || 0 guard prevents NaN from being displayed.

Common expressions

Sum a numeric field from all rows:

model?.reduce((sum, el) => sum + Number(el.fieldKey), 0) || 0

Count the number of rows:

model?.length || 0

Sum only rows where a condition is true:

model?.reduce((sum, el) => el.category === 'A' ? sum + Number(el.amount) : sum, 0) || 0