Skip to main content
Version: 2.5

Paths and Expressions

Choose the right path syntax​

Form Effects use several similar-looking values with different syntax. This is the most important distinction to remember:

PropertyExpected valueExample
listenA fully prefixed watched path$value.customer.id
field, from, toA literal form-control pathcustomer.id
when, set.valueA JEXL expression${$value.customer.id != null}
scriptData, runEffect.inputsValues or objects containing JEXL expressions{"id": "${$value.customer.id}"}
effectIdA literal effect IDprocess-customer
objectPointerA JSON Pointer to a widget in the schema/layout/0/items/2

Control paths use dot notation. Do not add $value, ${...}, or JSON Pointer slashes to field, from, or to. For an array, a legacy one-level effect may use items.$row.target. An effect with scope: "groups!.lines" uses groups!.lines!.target instead; each ! is bound to a concrete array row.

// Correct
{"type": "set", "field": "customer.email", "value": "${$value.contact.email}"}

// Incorrect: field is not a JEXL expression
{"type": "set", "field": "${$value.customer.email}", "value": "${$value.contact.email}"}
listen is the trigger, not automatic dependency discovery

Reading $value.customer.id in when, set.value, or scriptData does not automatically make the effect react to that field. Add every form value whose change should rerun the effect to listen. The designer warns when it detects a $value dependency that is not covered by listen.

Legacy listen entries that wrap a simple path in ${...} still work, but new effects should use a direct prefixed path.

Expression Context​

Availability

$trigger is available in tSM UI 2.4 builds that include TSM-4228. Older 2.4 deployments do not evaluate or suggest this variable.

Effect expressions use the same JEXL runtime as computed form properties, with an effect-specific scope:

ValueMeaning in a Form Effect
$valueCurrent value of the complete root form.
$contextForm context from the Fluent Forms store.
$outputContextOutput context from composed widgets and flows.
$configApplication/API configuration.
$configUiReserved for UI configuration. The current Form Effects runtime supplies {}, so do not depend on it yet.
$runtimeInfoCurrent user and runtime metadata.
$versionApplication version.
$buildBuild metadata.
$rowConcrete row index for a row-scoped value effect or array widget event; 0 when no row scope is present.
$itemCurrent row value in an effect with scope; for example, $item.source in when or value.
$parentsAncestor {row, item} entries for a scoped effect, nearest first. $parents[0].row is the immediately enclosing array's row index.
dataSourcesRegistered datasource functions.
dataSourcesValuesSettled datasource values available to the evaluator.
$dataSourcesLoadingWhether an expression datasource is still resolving.
$eventComplete semantic event in a widget-event effect.
$payloadShorthand for $event.payload.
$inputEvaluated input object in an invoked effect.
$responseScript result in the script's direct outcome branch.
$triggerTransient cause of the current effect run, including the immediate change origin and the initiator of the complete effect chain.

The stage-specific values are preserved in a script outcome branch belonging to that same effect. An invoked effect receives only the values explicitly mapped into $input.

For nested arrays, listen watches a $value variable path such as $value.groups!.lines!.source. When scope names the matching array, ! binds its row positions in listen and literal action paths. Use $item, $row, and $parents inside JEXL expressions. See the nested-array example.

Use $trigger.origin when an effect must react only to a direct user edit:

$trigger.origin == 'user'

Effect actions set the next run's immediate origin to effect. To include later effect-written values from the same user-started cascade, test $trigger.initiator == 'user' instead. Other useful metadata includes $trigger.type (valueChange, widgetEvent, invoked, or initialization) and $trigger.changes, which lists the relevant changed paths and their origins.

$trigger is available only while an effect is executing; it is not form data and is not available in ordinary widget expressions. See the complete $trigger attribute reference for type, origin, initiator, individual changes, chainId, and parentEffectId.

Member access​

Author ordinary dot and bracket access in Form Effects expressions:

$value.customer.address.street
$response.items[0].name

The expression compiler adds safe member access. Do not add JavaScript optional access operators such as ?. to persisted Form Effects expressions. Use a fallback when the final result can be missing:

$value.customer.address.street || 'N/A'

See the JEXL language reference for operators, functions, transforms, and Public API data sources.

Datasources​

Only datasources declared for effect usage can be called from an effect expression. The current runtime resolves datasource calls in when, set.value, and runEffect.inputs; it does not resolve them in scriptData:

Effect modeRuntime behavior
plainValueResolve a scalar or object value on the first emission.
identifiedPackWait until the returned pack has loading !== true. Read the result from .data.
unsupportedReject the datasource in an effect and omit it from effect autocomplete.

Example using an identifiedPack datasource:

{
"id": "load-user-name",
"listen": ["$value.userId"],
"do": [
{
"type": "set",
"field": "userName",
"value": "${evalScriptByCode('GetUserName').data}"
}
]
}

Datasource parameters are reevaluated when their dependencies change. A new value-change run supersedes an older synchronous run that has not completed.