JEXL Runtime And Public API
Runtime Calls: Helpers, Data Sources, And Public API
JEXL expressions can call three kinds of runtime functionality.
| Kind | Examples | Use for |
|---|---|---|
| In-memory helpers | isNullOrEmpty, includes, dateFormat, sumMany | Cheap formatting, checks, array mapping, calculations. |
| Runtime/data-source helpers | evalScriptByCode, attachmentCount, tsmModule, datePlusWorkdays | Calls that read another runtime service or configured script. |
| Public API entity calls | crm.customer.get(...), order.order.find(...), user.user.get(...) | Direct entity reads from tSM Public API. |
Prefer in-memory helpers inside frequently recalculated UI properties. Guard runtime and API calls with a condition so they do not run when required input is missing:
!isNullOrEmpty($context.form.customerId)
? crm.customer.get($context.form.customerId)
: null
Public API Calls
JEXL can call tSM Public API using this form:
<service>.<entity>.<method>(arguments...)
Examples:
crm.customer.get($context.form.customerId)
crm.customer.find({ code: $context.form.customerCode })
config.registerValue.get($context.entity.statusId, { expand: ['REGISTER'] })
Segments:
| Segment | Example | Meaning |
|---|---|---|
service | crm | Microservice or logical API area. |
entity | customer | Entity in the service. |
method | get, find | Operation on the entity. |
Every call can trigger an HTTP request. The platform can cache results, but UI expressions must still be designed with latency in mind. Avoid placing Public API calls into expressions that are evaluated repeatedly during every small field change unless it is necessary.
Public API Filter Operators
Filters use suffixes on field names:
crm.account.find({ code__in: $context.form.accountCodes })
ticket.ticket.find({ createdAt__gte: $context.form.dateFrom })
Supported suffixes:
| Suffix | Meaning | Example |
|---|---|---|
__contains | contains value | { name__contains: 'slovanet' } |
__notcontains | does not contain value | { name__notcontains: 'test' } |
__startswith | starts with value | { code__startswith: 'BA' } |
__endswith | ends with value | { code__endswith: '01' } |
__in | value is in list | { code__in: ['A', 'B'] } |
__notin | value is not in list | { code__notin: ['A', 'B'] } |
__eq | equals | { status__eq: 'ACTIVE' } |
__noteq | does not equal | { status__noteq: 'CANCELLED' } |
__gt | greater than | { amount__gt: 10 } |
__gte | greater than or equal | { amount__gte: 10 } |
__lt | less than | { amount__lt: 10 } |
__lte | less than or equal | { amount__lte: 10 } |
__empty | empty value | { field__empty: true } |
__notempty | non-empty value | { field__notempty: true } |
__btw | between values | { amount__btw: '10-15' } |
__gtr | greater than relative time | { date__gtr: '-1d' } |
__ltr | less than relative time | { date__ltr: '+1d' } |
__btwr | between relative times | { date__btwr: '-1d:+1d' } |
__dontTouch | leave value untouched | { field__dontTouch: 'customFunction()' } |
__fuzzyContains | fuzzy contains for Elastic/TQL cases | { name__fuzzyContains: 'slovanet' } |
JEXL vs SpEL
JEXL and SpEL solve different problems in tSM.
| Topic | JEXL | SpEL |
|---|---|---|
| Runtime | Frontend/UI runtime. | Backend/server runtime. |
| Typical place | Forms, widgets, data-source parameters, UI validations. | Processes, scripts, automation, backend orchestration. |
| Context style | $context, $value, $row, $configUi. | #variables, #context, Spring beans/services. |
| Expression shape | Usually one expression returning a value. | Can be a longer script-like expression with assignments and service calls. |
| Side effects | Avoid side effects; UI expressions can re-evaluate often. | Side effects are expected in process/script logic when intentionally designed. |
| Transactions | No backend transaction boundary. | Can run as part of backend process/script execution. |
| Best use | Visibility, required state, default values, filters, small transformations. | Persisting changes, process transitions, integration logic, complex business rules. |
Rule of thumb: if the expression only decides how the current UI behaves, use JEXL. If it changes server-side state, coordinates multiple entities, or has integration side effects, use SpEL or a backend script and call it from JEXL only when needed.