Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.kodexa.ai/llms.txt

Use this file to discover all available pages before exploring further.

Event-based scripting belongs to Data Definitions. It is how the data model reacts when values change. A Data Form renders the review experience for a Task. A Data Definition owns the structure and behavior of the business data being reviewed. Event subscriptions let that data model run JavaScript when an event occurs, such as an attribute changing on a data object. Use event scripts when a change to one field should update other fields, call an external system, create an exception, emit another event, or apply business logic that is too procedural for a formula.

When To Use Event Scripts

Use an event subscription when the data definition needs behavior, not just structure:
  • Derive several sibling attributes after a reviewer edits one value
  • Normalize data before formulas, validation, and selection rules run
  • Call a Service Bridge to enrich a row from an external system
  • Create or close data exceptions based on business logic
  • Copy or move data objects when a modeled relationship changes
  • Emit a named event that another subscription can handle
Use a formula when one output value can be computed declaratively from other values. Use event scripting when the change has side effects or needs multiple reads and writes.

Where Event Scripts Run

Event subscriptions are attached to group data elements in a Data Definition. In configuration, those group elements are stored as taxons. At runtime, the script executes for one data object instance of that group. The script runs inside the recalculation flow. Writes made by the script are visible to downstream formula recalculation, selection option evaluation, validation, selection validation, and conditional formatting.

Configuration

Attach eventSubscriptions to a group data element:
- name: shipment
  label: Shipment
  group: true
  eventSubscriptions:
    - name: compute-accessorial-total
      on: "changed:dataAttribute:(quantity|unit_price)"
      script: |
        if (!currentObject) return;

        var quantity = currentObject.getFirstAttributeValue("quantity") || 0;
        var unitPrice = currentObject.getFirstAttributeValue("unit_price") || 0;

        currentObject.setAttribute("line_total", quantity * unitPrice);
  children:
    - name: quantity
      label: Quantity
      taxonType: NUMBER
    - name: unit_price
      label: Unit Price
      taxonType: NUMBER
    - name: line_total
      label: Line Total
      taxonType: NUMBER

Attribute Change Shorthand

For simple attribute-change subscriptions, dependsOn is a compact way to list the attributes that should trigger the script:
eventSubscriptions:
  - name: compute-accessorial-total
    on: "changed:dataAttribute"
    dependsOn:
      - quantity
      - unit_price
    script: |
      currentObject.setAttribute("line_total", 0);
Kodexa expands that into the equivalent event pattern:
on: "changed:dataAttribute:(quantity|unit_price)"
Use the explicit on form when you need to match multiple event types or a custom event pattern.

Fields

name
string
required
Unique name for the subscription within the owning group data element. The runtime uses this name for loop-control state and diagnostics.
on
string
required
Regex pattern matched against the full event string. Kodexa anchors the pattern internally, so changed:dataAttribute:amount matches only that event string.
dependsOn
string[]
Convenience field for changed:dataAttribute. When present with on: "changed:dataAttribute", validation converts it to an on regex and clears dependsOn.
script
string
required
JavaScript source executed for the subscription run.
disabled
boolean
default:"false"
When true, the subscription remains in the Data Definition but is skipped at runtime.

Supported Event Strings

The subscription matcher uses full event strings.
Event stringHow it is used
changed:dataAttribute:field_nameFired when a data attribute changes. This is the main automatic data-definition event.
created:dataObjectFired by the document runtime when a data object is created.
loaded:dataObjectFired after initial document load in the browser runtime.
formLoaded:form_refMatches form-load events emitted by the host.
trigger:nameMatches named events emitted by script or host code.
focus:dataAttribute:field_nameMatchable event for focus-aware hosts.
blur:dataAttribute:field_nameMatchable event for blur-aware hosts.
For common attribute-change subscriptions, use:
on: "changed:dataAttribute:(shipper_city|shipper_state|postal_code)"
For a named event:
on: "trigger:recalculate-rating"
For multiple event types:
on: "(loaded:dataObject|trigger:recalculate-rating)"

Runtime Rules

RuleDetail
RuntimeJavaScript VM
Timeout2 seconds per subscription execution
VM lifetimeFresh VM per subscription execution
AsyncNo async / await; calls are synchronous
Document scopeUse the prebound document; loadDocument() is not supported for subscription scripts
Attribute writesUse currentObject.setAttribute(name, value)
Type safetyTyped setters validate against the attribute type

Execution Order

When a data attribute changes, Kodexa processes the cascade in this order:
1. Mark the attribute dirty
2. Emit the attribute-changed event
3. Run matching event subscriptions
4. Recalculate dependent formulas
5. Re-evaluate affected selection option formulas
6. Evaluate affected validations
7. Validate selections
8. Evaluate affected conditional formats
This ordering matters. If an event script writes tax_rate, formulas and validations that depend on tax_rate see the value written by the script.

Script Globals

Every event subscription receives a small set of prebound globals.
GlobalAvailableUse
currentObjectAll subscription scriptsThe group data object instance that owns the event. May be null; guard before use.
documentAll subscription scriptsThe active document containing currentObject.
eventAll subscription scriptsEvent payload with the event string, changed attribute, old value, new value, and data object id.
serviceBridgeSubscription runtimes with platform transportCalls configured Service Bridges through the platform proxy.
taxonBrowser subscription runtimeLooks up selection option labels from loaded Data Definitions.
bridgeBrowser subscription runtimeUI/event hooks such as notifications and explicit event firing. Guard before use for cross-runtime scripts.
logAll subscription scriptsStructured logging with debug, info, warn, and error.
consoleAll subscription scriptsBrowser-style logging aliases.

event

The event object describes why the script ran.
PropertyTypeDescription
typestringFull event string, such as changed:dataAttribute:amount
eventKindstringEvent prefix, such as changed:dataAttribute, when supplied by the host
attributeTagstringChanged attribute name for attribute events
attributePathstringFull attribute path when available
dataObjectIdnumberID of the data object where the event occurred
oldValueanyTyped value before the change
newValueanyTyped value after the change
formNamestringForm reference for formLoaded:* events
triggerNamestringTrigger name for trigger:* events
Example:
if (event.attributeTag === "amount") {
  log.info("Amount changed from", event.oldValue, "to", event.newValue);
}

currentObject

currentObject is the data object instance for the group data element where the event matched.

Reading Values

MethodReturnsUse
getPath()stringData object definition path
getIDString()stringData object ID as a string
getParent()DataObject or nullParent data object
getChildren()DataObject[]Child objects already attached to this object
getChildrenByPath(path)DataObject[]Direct children matching a path
getAttributeByName(name)DataAttribute or nullFirst matching attribute wrapper
getAttributesByName(name)DataAttribute[]All matching attribute wrappers
getFirstAttributeValue(name)string, number, boolean, string date, or undefinedFirst typed attribute value
getAttributeValues(name)string[]All matching values stringified
hasTaxonomy()booleanWhether the object has a Data Definition reference
if (!currentObject) return;

var city = currentObject.getFirstAttributeValue("shipper_city");
var state = currentObject.getFirstAttributeValue("shipper_state");
var path = currentObject.getPath();

log.debug("Changed object", path, city, state);

Writing Values

Use setAttribute(name, value) for normal writes. It finds or creates the attribute, resolves the target type from the Data Definition when available, writes the typed value, persists the change, and notifies the recalculation system.
var quantity = currentObject.getFirstAttributeValue("quantity") || 0;
var price = currentObject.getFirstAttributeValue("unit_price") || 0;

currentObject.setAttribute("line_total", quantity * price);
Supported value types are strings, numbers, booleans, and RFC 3339 date strings for date attributes.
Type mismatches fail the script. For example, writing "abc" to a numeric data element raises a JavaScript error from the typed setter.

Payloads For Service Bridges

payload(mapping) builds a plain JavaScript object from attributes on currentObject.
var body = currentObject.payload({
  shipperCode: "shipper_code",
  shipperCity: "shipper_city",
  shipperState: "shipper_state"
});

// { shipperCode: "ACME", shipperCity: "Chicago", shipperState: "IL" }
Missing attributes are returned as empty strings. This keeps Service Bridge request bodies stable.

Creating Child Data Objects

Use getOrCreateChild(path, opts?) or addChild(opts) when the event should create modeled child data.
var accessorial = currentObject.getOrCreateChild("shipment/accessorials", {
  sourceOrdering: "0"
});

accessorial.setAttribute("code", "LIFTGATE");
accessorial.setAttribute("amount", 75);
Use copyAttributesFrom(sourceObj, mappings, ownerUri?) when moving known attributes between objects:
target.copyAttributesFrom(source, [
  { src: "invoice_number" },
  { src: "currency", dst: "amount_currency" }
]);

DataAttribute

getAttributeByName() and getAttributesByName() return attribute wrappers for lower-level operations.
MethodUse
getTag()Attribute tag/name
getPath()Full attribute path
getOwnerUri()Audit owner URI
getValue()Raw value
getStringValue()Typed string value
getDecimalValue()Typed numeric value
getBooleanValue()Typed boolean value
getDateValue()Typed date value as RFC 3339
getConfidence()Confidence value, or 0 when absent
getDataFeatures()Attribute data features
setStringValue(value)Persist typed string value
setDecimalValue(value)Persist typed numeric value
setBooleanValue(value)Persist typed boolean value
setDateValue(value)Persist typed date value from RFC 3339 string
setConfidence(value)Persist confidence
addFeature(key, value)Add a data feature
Prefer currentObject.setAttribute(...) for common writes. Use DataAttribute methods only when you need direct access to a specific attribute instance.

document

The document global is the active KDDB document.

Data Object Access

MethodUse
getAllDataObjects()Return all data objects
findDataObjectsByPath(path)Return all objects for a path
findFirstDataObjectByPath(path)Return the first object for a path
getOrCreate(path, opts?)Find or create a top-level data object
createDataObject(opts)Create a data object
deleteDataObject(id)Delete a data object
copyDataObject(opts)Copy a data object
moveDataObject(opts)Move a data object
batchCopyDataObjects(opts[])Copy several objects atomically
batchMoveDataObjects(opts[])Move several objects atomically
updateDataObject(obj)Persist in-memory object changes
getDataObjectsByParentId(parentId)Return direct children for a parent ID

Document Metadata And External Data

MethodUse
getUUID() / getVersion()Document identity
getLabels() / addLabel(label) / removeLabel(label)Document labels
getMetadata() / setMetadata(key, value)Document metadata map
getDocumentMetadataMap()Copy of document metadata
getDocumentMetadataValue(key)Single document metadata value
setDocumentMetadataValue(key, value)Set or delete document metadata value
getExternalData(key)External data entry
setExternalData(key, data)Write external data
getExternalDataKeys()External data keys

Content, Search, And Serialization

MethodUse
getRootNode() / getContentNode()Access the document content tree
select(selector, variables)Select content nodes
selectFirst(selector, variables)Select the first matching node
getAllTags()Unique document tags
searchContent(pattern, opts)Regex content search
searchLines(query, opts)Line search
getSearchableLines()Searchable line records
toJSON()Serialize document metadata and data objects
dataObjectsToJSON()Serialize data objects only

Exceptions And Validations

MethodUse
createDataException(opts)Create a data exception
updateDataException(opts)Update a data exception
closeDataException(id, comment)Close a data exception
reopenDataException(id)Reopen a data exception
getAllDataExceptions()All data exceptions
getOpenDataExceptions()Open data exceptions
getDataExceptionById(id)One data exception
getDataExceptionsByDataObjectId(id)Exceptions for a data object
addValidation(opts)Add validation metadata
getValidations() / setValidations(opts)Read or replace validations
validateDocument()Run document validation
Example:
var amount = currentObject.getFirstAttributeValue("amount");

if (!amount || amount <= 0) {
  document.createDataException({
    message: "Amount must be greater than zero",
    exceptionType: "validation",
    severity: "error",
    dataObjectId: event.dataObjectId
  });
}

serviceBridge

serviceBridge.call(bridgeRef, endpointName, body?) calls an external system through a configured Service Bridge.
var result = serviceBridge.call(
  "acme-finance/vendor-lookup",
  "match-vendor",
  currentObject.payload({
    vendorName: "vendor_name",
    postalCode: "postal_code"
  })
);

if (result && result.vendorId) {
  currentObject.setAttribute("vendor_id", result.vendorId);
  currentObject.setAttribute("vendor_match_status", "matched");
}
Bridge refs may be fully qualified as orgSlug/bridgeSlug. Some runtimes can supply a default organization slug, but fully qualifying the bridge keeps scripts portable. The bridge response is parsed as JSON. If the platform proxy returns a result envelope, the runtime returns the result value directly. If the proxy returns an error envelope, the script fails with that error.

taxon

In the browser subscription runtime, taxon.optionLabel(taxonName, value) returns the display label for a selection option value.
var movementType = currentObject.getFirstAttributeValue("movement_type");
var label = taxon.optionLabel("movement_type", movementType);

if (label) {
  currentObject.setAttribute("movement_type_label", label);
}
Guard this helper if the same script may run in a runtime that has not loaded Data Definition bindings:
if (typeof taxon !== "undefined") {
  var label = taxon.optionLabel("movement_type", value);
}

bridge

The browser subscription runtime exposes bridge for UI notifications and explicit event emission.
MethodUse
bridge.notify(title, message, severity?)Show a user notification. Severity defaults to info.
bridge.events.fire(eventString, dataObjectId?)Emit another event into the recalculation cascade.
if (typeof bridge !== "undefined") {
  bridge.notify("Vendor matched", "Vendor ID was populated.", "success");
}
Fire a follow-up event when another subscription should respond:
if (typeof bridge !== "undefined") {
  bridge.events.fire("trigger:recalculate-rating", event.dataObjectId);
}
Only emit events deliberately. Emitted events participate in the same loop-control rules as automatic events.

Logging

Use structured logging during development and troubleshooting:
log.debug("event", event.type, "object", currentObject.getPath());
log.info("vendor response", JSON.stringify(result));
log.warn("missing postal code");
log.error("unexpected response shape", JSON.stringify(result));
console.log, console.warn, and console.error are also available.

Loop Control

The recalculation service protects event scripts from runaway cascades:
GuardBehavior
Active frame guardA subscription cannot re-enter itself while already running for the same data object.
Cascade deduplicationA subscription runs at most once per data object in one user-driven cascade.
Maximum depthNested event execution is capped at 8 levels.
No-op suppressionWrites that do not change typed values are suppressed.
Design scripts to be idempotent. A script may run more than once over the life of a document, and retries should not duplicate data or re-open resolved work.

Examples

Normalize And Derive Sibling Values

eventSubscriptions:
  - name: normalize-postal-code
    on: "changed:dataAttribute:postal_code"
    script: |
      if (!currentObject) return;

      var postalCode = currentObject.getFirstAttributeValue("postal_code");
      if (!postalCode) return;

      currentObject.setAttribute("postal_code", String(postalCode).trim().toUpperCase());
      currentObject.setAttribute("postal_code_prefix", String(postalCode).slice(0, 5));

Service Bridge Enrichment

eventSubscriptions:
  - name: lookup-vendor
    on: "changed:dataAttribute:(vendor_name|postal_code)"
    script: |
      if (!currentObject) return;

      var vendorName = currentObject.getFirstAttributeValue("vendor_name");
      if (!vendorName) return;

      var result = serviceBridge.call(
        "acme-finance/vendor-lookup",
        "match-vendor",
        currentObject.payload({
          vendorName: "vendor_name",
          postalCode: "postal_code"
        })
      );

      if (result && result.vendorId) {
        currentObject.setAttribute("vendor_id", result.vendorId);
        currentObject.setAttribute("vendor_match_status", "matched");
      } else {
        currentObject.setAttribute("vendor_match_status", "review");
      }

Create A Data Exception

eventSubscriptions:
  - name: validate-amount
    on: "changed:dataAttribute:amount"
    script: |
      if (!currentObject) return;

      var amount = currentObject.getFirstAttributeValue("amount");
      if (amount === undefined || amount === null || amount <= 0) {
        document.createDataException({
          message: "Amount must be greater than zero",
          exceptionType: "validation",
          severity: "error",
          dataObjectId: event.dataObjectId
        });
      }

Emit A Follow-Up Event

eventSubscriptions:
  - name: vendor-change
    on: "changed:dataAttribute:vendor_id"
    script: |
      if (typeof bridge !== "undefined") {
        bridge.events.fire("trigger:recalculate-risk", event.dataObjectId);
      }

  - name: recalculate-risk
    on: "trigger:recalculate-risk"
    script: |
      if (!currentObject) return;
      var amount = currentObject.getFirstAttributeValue("amount") || 0;
      var vendorStatus = currentObject.getFirstAttributeValue("vendor_status");
      currentObject.setAttribute(
        "risk_level",
        amount > 10000 || vendorStatus === "new" ? "review" : "standard"
      );

Constraints

Event subscriptions can only be declared on group data elements.
Scripts run synchronously with a 2-second timeout. Keep external calls bounded and avoid large document scans.
Subscription scripts are scoped to the active document. Use the prebound document global; do not call loadDocument().

Best Practices

Name the exact business event the script responds to. Prefer specific on patterns such as changed:dataAttribute:(quantity|unit_price) over broad matches.
Read and write values on currentObject when possible. Use document only when the script really needs broader document context.
Write the same result for the same inputs. Avoid appending duplicate child objects or recreating exceptions without checking existing state.
getFirstAttributeValue returns typed values. Preserve those types when writing with setAttribute.
Wrap bridge and the taxon helper usage in typeof ... !== "undefined" checks when a script may also run outside the browser runtime.
Use log.debug while building and keep production logs focused on decisions, external calls, and unexpected states.

Data Definitions

Define the data model that event scripts operate on

Data Definition Structure

Configure data elements, groups, validations, selection options, and event subscriptions

Selection Option Formulas

Compute dynamic selection options from data and bridge calls

Service Bridges

Configure external API calls used by event scripts