Skip to main content
Event subscriptions let you attach JavaScript scripts to group taxons that run automatically when specified child attributes change. Use them to derive values, enforce business rules, call external systems, or synchronize related fields — all triggered reactively as users edit data. Event subscriptions are a powerful complement to formulas: while formulas compute a single output value from inputs, event subscriptions can read and write multiple attributes, call service bridges, and implement complex business logic.

Key Concepts

Event Subscription

A named script attached to a group taxon that runs in response to data changes

Trigger Event

The event type that activates the subscription (changed:dataAttribute in v1)

DependsOn

List of direct child taxon names that trigger the subscription when they change

Script

JavaScript code executed by the GoJA runtime when the event fires

Configuration Reference

A complete event subscription configuration in YAML:
- name: line_items
  label: Line Items
  group: true
  eventSubscriptions:
    - name: lookup-tax-rate
      on: "changed:dataAttribute"
      dependsOn:
        - country
        - region
      script: |
        if (!currentObject) return;
        
        var country = currentObject.GetFirstAttributeValue("country");
        var region = currentObject.GetFirstAttributeValue("region");
        
        if (country && region) {
          var result = serviceBridge.call(
            "myorg/tax-rates",
            "get-rate",
            { country: country, region: region }
          );
          
          if (result && result.taxRate !== undefined) {
            bridge.data.setAttribute(
              currentObject.GetID(),
              "tax_rate",
              result.taxRate
            );
          }
        }
  children:
    - name: country
      label: Country
      taxonType: STRING
    - name: region
      label: Region
      taxonType: STRING
    - name: tax_rate
      label: Tax Rate
      taxonType: NUMBER

Properties

name
string
required
Unique identifier for the subscription within the owning group taxon. Use lowercase with hyphens (e.g., lookup-tax-rate).
on
string
required
Event type. Must be "changed:dataAttribute" (the only supported type in the current version).
dependsOn
string[]
required
List of direct child taxon names that trigger this subscription. Must reference actual children of the owning group. At least one entry required. No nested paths allowed (e.g., "city" not "address/city").
script
string
required
JavaScript code executed when the event fires. Runs in the GoJA runtime with a 2-second timeout.
disabled
boolean
default:"false"
When true, the subscription is skipped during execution but still validated. Useful for temporarily disabling without removing.

Supported Events

Event TypeTriggerDescription
changed:dataAttributeUser edits an attribute valueFires when any attribute listed in dependsOn changes on a data object instance of this group
Additional event types (e.g., created:dataObject, deleted:dataAttribute) may be added in future versions. Currently only changed:dataAttribute is supported.

Script Globals

When an event subscription script executes, these globals are available:
GlobalTypeDescription
currentObjectobjectThe group data object instance where the change occurred
eventobjectDetails about the triggering change
bridge.data.getAttribute(id, tag)functionRead an attribute value from a data object
bridge.data.setAttribute(id, tag, value)functionWrite an attribute value on a data object
serviceBridge.call(ref, endpoint, body)functionCall an external API via a service bridge
log(level, message)functionWrite to server logs (debug, info, warn, error)
console.log(...)functionStandard console logging

The event Object

PropertyTypeDescription
typestringAlways "changed:dataAttribute"
attributeTagstringName of the changed attribute (e.g., "country")
attributePathstringFull path (e.g., "line_items/country")
dataObjectIdnumberID of the data object that changed
oldValueanyPrevious value before the change
newValueanyNew value after the change

The currentObject API

MethodReturnsDescription
GetID()numberData object ID (use with bridge.data.setAttribute)
GetIDString()stringData object ID as string
GetPath()stringTaxonomy path of the data object
GetFirstAttributeValue(name)anyCurrent typed value of the named attribute
GetAttributeValues(name)string[]All values of the named attribute as strings

Reading and Writing Attributes

Reading:
// Read from the current object
var country = currentObject.GetFirstAttributeValue("country");

// Read from any data object by ID
var value = bridge.data.getAttribute(currentObject.GetID(), "region");
Writing:
// Write to a sibling attribute on the same data object
bridge.data.setAttribute(currentObject.GetID(), "tax_rate", 0.08);
bridge.data.setAttribute() routes through typed setters. The value type must match the target taxon’s type. Writing a string to a NUMBER taxon or vice versa will throw an error.
Writes that don’t change the value are automatically suppressed (no-op detection). This prevents infinite loops when a subscription writes the same value it already has.

Execution Order

When an attribute changes, the platform processes the change in this order:
1. Attribute value updated
2. Attribute change event emitted
3. Event subscriptions execute          <-- your script runs here
4. Formula recalculation
5. Selection option formula re-evaluation
6. Validation rules evaluated
7. Selection validation
8. Conditional formatting applied
This means subscription scripts can write values that formulas will then see in step 4. A subscription that sets tax_rate will have that value available to any formula referencing tax_rate.

Loop Control

The platform includes three levels of protection against infinite loops:
A subscription cannot trigger itself while it is already running for the same data object. If subscription A writes to an attribute that would trigger subscription A again, the re-trigger is blocked.
Within a single user edit cascade, each subscription fires at most once per data object. If subscription A triggers subscription B which tries to re-trigger A, the second A invocation is skipped.
A hard limit of 8 nested invocations protects against complex mutual recursion. If the cascade depth exceeds 8, execution stops.
Combined with no-op suppression on writes, these guards ensure scripts terminate reliably.

Examples

Derive a field from siblings

eventSubscriptions:
  - name: compute-total
    on: "changed:dataAttribute"
    dependsOn:
      - quantity
      - unit_price
    script: |
      if (!currentObject) return;
      
      var qty = currentObject.GetFirstAttributeValue("quantity");
      var price = currentObject.GetFirstAttributeValue("unit_price");
      
      if (qty !== undefined && price !== undefined) {
        var total = qty * price;
        bridge.data.setAttribute(currentObject.GetID(), "line_total", total);
      }

External lookup on change

eventSubscriptions:
  - name: lookup-employee-details
    on: "changed:dataAttribute"
    dependsOn:
      - employee_id
    script: |
      if (!currentObject) return;
      
      var employeeId = currentObject.GetFirstAttributeValue("employee_id");
      if (!employeeId) return;
      
      var employee = serviceBridge.call(
        "myorg/directory",
        "get-employee",
        { id: employeeId }
      );
      
      if (employee) {
        bridge.data.setAttribute(currentObject.GetID(), "employee_name", employee.name);
        bridge.data.setAttribute(currentObject.GetID(), "employee_email", employee.email);
      }

Conditional flag setting

eventSubscriptions:
  - name: flag-high-value
    on: "changed:dataAttribute"
    dependsOn:
      - amount
    script: |
      if (!currentObject) return;
      
      var amount = currentObject.GetFirstAttributeValue("amount");
      var flag = (amount && amount > 10000) ? "High Value" : "Standard";
      bridge.data.setAttribute(currentObject.GetID(), "review_flag", flag);

Constraints

Event subscriptions can only be attached to group taxons (taxons with group: true).
dependsOn must list direct children of the group — no nested paths.
Each subscription name must be unique within its owning group.
Scripts have a 2-second timeout — keep logic fast.
No async/await — all operations are synchronous.
Only changed:dataAttribute is supported as an event type in the current version.
Scripts cannot create or delete data objects — they can only read and write attribute values.

Best Practices

Always start with if (!currentObject) return; as a guard. This protects against edge cases where the data object context is not available.
Keep scripts focused on a single responsibility. If you need multiple behaviors, create separate subscriptions with clear names.
Use descriptive subscription names that indicate what the script does. Names like compute-total or lookup-employee-details are clearer than script-1.
Test with simple values before connecting service bridges. Verify that reads and writes work correctly before adding external API calls.
Use log("debug", ...) during development, then set disabled: true or remove debug logs for production.
If a script does not need to run temporarily, use disabled: true rather than removing it. This preserves the configuration for future use.

Formulas Guide

Compute single output values from attribute inputs

Service Bridges

Call external APIs through pre-configured proxies

Data Definitions

Define and configure data structures for extraction

Taxonomy Guide

Comprehensive reference for all taxonomy configuration options