AI: Logic and expression properties
This page defines which expression fields the agent may use and which rules it must follow.
Primary expression properties
| Property | When to use | Must return |
|---|---|---|
visibleIf | Show an element (native field; return false to hide) | true or false |
disableIf | Make an element inactive | true or false |
requireIf | Make an element required | true or false |
readonlyIf | Make an element read-only | true or false |
resetIf | Clear an element under a condition | true or false |
expression | Compute and write a value | string, number, boolean, array, or object |
validators[].applyIf | Enable a validator conditionally | true or false |
validators[].condition | Failing check, error shown while true | true or false |
Other expression usage points
The agent must know that expression logic does not live only in the main fields.
Data source parameters
The field is called params, never paramMap:
- an element's
dataSource.params[*].value, shaped[{ "name": ..., "value": ... }] - an action's
params[*].value, the same shape - a
table's own lazy-load request params, which are different:[{ "paramName": ..., "paramValue": ... }] {placeholder}tokens inside a REST source'sparams.urlandparams.body
These can use expression fragments such as:
{personCode}
{row.id}
{__variables.route.mode}Table columns
table.columnsConfig[*] can use:
visibleIfcontrolActiveIfcontrolEnabledIf
Inside a column of type: "element", the hosted element's own texts, templates, and event params resolve against the row it renders: {row.field}, a bare {field} for a sibling of the same row, {index}, and {value}. The same tokens work in a dynamicTable cell and a dynamicPanel row.
Event and action logic
Expressions are often used in actions in:
params[*].valuecondition, which gates whether the action runs at all (per row for a table row action)setValueValuewhensetValueModeistemplateorexpression
When to use logicExecutionMode
If there is a dependency between fields, especially when expression is used, you typically need:
{
"logicExecutionMode": "onChange"
}This is especially important when:
- one field fills another
- one field changes another's required state
- one field hides or disables another
Core writing rules
- Use only NGX View Builder expression syntax, not full
JavaScript. - Read field values via
{fieldName}or{object.field}. - Use quotes for string values.
- Do not add
toNumber(...)by reflex. Number elements already hold numbers, so{price} * {quantity}works as written. Reach for it only when the value genuinely arrives as text: atextelement, a data source field, a select whose values are strings, or a number element withvalueStorageType: "string". - Use
isEmpty(...)andnotEmpty(...)for empty checks. - Use
contains,containsAny,containsAll, andlenfor arrays.
Correct examples
Auto-fill
{
"name": "lastName",
"type": "text",
"expression": "{firstName} == 'John' ? 'Doe' : ''",
"logicExecutionMode": "onChange"
}Conditional required
{
"name": "companyCode",
"type": "text",
"requireIf": "{personType} == 'company'",
"logicExecutionMode": "onChange"
}Show/hide
{
"name": "vatCode",
"type": "text",
"visibleIf": "{country} == 'LT'"
}Calculation
{
"name": "totalAmount",
"type": "number",
"expression": "{price} * {quantity}",
"logicExecutionMode": "onChange"
}Bad examples
Self-reference expression
Incorrect:
{
"name": "el2",
"expression": "{el1} == 'John' ? 'Doe' : {el2}"
}Why it is wrong:
- the element references itself
- this leads to unstable or non-functioning logic
Correct:
{
"name": "el2",
"expression": "{el1} == 'John' ? 'Doe' : ''",
"logicExecutionMode": "onChange"
}Wrong type for a boolean property
Incorrect:
{
"visibleIf": "'yes'"
}visibleIf must return true or false, not a string.
Reference to a non-existent field
Incorrect:
{
"disableIf": "{customerType} == 'vip'"
}if customerType does not exist in the form.
Expression property map by need
| Need | Property |
|---|---|
| Show/hide a field | visibleIf (return false to hide) |
| Show but prevent editing | disableIf or readonlyIf |
| Make required only in certain cases | requireIf |
| Reset value when condition changes | resetIf |
| Automatically compute a value | expression |
| Enable a validator conditionally | validators[].applyIf |
| Flag a custom validation error | validators[].condition (error while true) |
Working with arrays and element metadata
Conditions inside collection functions are written unquoted and evaluated once per entry. Entry fields are referenced bare, everything else in the view stays reachable through {...}:
countInArray({tasks}, status == "OPEN")
filterArray({users}, role == {__variables.requiredRole})
findInArray({products}, id == {selectedId})
existsInArray({items}, status == "ACTIVE")
sumArray({orderItems}, price)
joinInArray(mapArray(filterArray({tasks}, status == "OPEN"), title), "", ", ")Also available: avgArray, getFirst(source, condition?), getLast(source, condition?). countInArray still accepts a plain field selector, so older structures keep working.
For element metadata rather than values:
| Call | Returns |
|---|---|
getValue({select1}) | stored value, e.g. OPEN |
getLabel({select1}) | displayed option label, e.g. Open issue |
getLabel("select1", "CLOSED") | label of a specific value |
getElementProperty("el1", "label") | any configured property, nested keys allowed |
getProp({el1}, "placeholder") | alias of getElementProperty |
translate({row.status}) | value translated through localization.texts[<language>] |
currentLanguage() | active language code |
In getLabel, getValue, and getProp the token names the element, it is not replaced by that element's value.
Writing values from an expression
| Call | Does |
|---|---|
setValue({variable1}, value) | writes into a variable or an element data path |
sumValue({variable1}, value) | adds a number to the current value, returns the new total |
pushValue({variable1}, value) | appends to the target's array |
flattenArray(source) | flattens nested arrays into one level |
setVar, sumVar, and pushVar are the same calls with the target always read as a variable name. addValue is an alias of sumValue.
Shorthand, where the leftmost token is the target and the right side reads normally:
{variable1} = {row.column3} + 40
{variable1} += {row.column3}Rules for the agent:
- The first argument names the target, do not replace it with a value.
setValueis safe in a recalculated expression, writing an unchanged value does nothing.sumValueandpushValueadd again on every run, so put them in an action, never invisibleIf,disableIf, or anexpressionproperty.- For a table inside a dynamic panel prefer one aggregate over accumulation:
setValue({variable1}, sumArray({el1}, el5[].column3)). - A published column total is read as
{el4.column1-total}, always in braces.
Contexts the agent may encounter
General form context
{fieldName}{nested.field}{__variables.*}
Dynamic blocks and tables
{row.field}inside atablecell, adynamicTablerow, a row action or a column template{panel.field}inside adynamicPanelentry{item.field}for the candidate option infilterOptionsBy{index}and{value}inside a cell- a published
dynamicTablecolumn total,{el1.column4-total}
A table's own live state
A table publishes its state so other elements can read it. __table.<tableName>.* is that table, bare __table.* is the last one touched:
rows allRows rowCount totalRecords page size sortField sortDirection quickSearch detailedFilters request selectedRows selectedKeys selectedItems selectedCount selectedRow selectedRowKey selectedRowIndex activeRow activeRowKey
{__table.el2.selectedCount} > 0
notEmpty({__table.el2.selectedRowKey})
{__table.el2.selectedRow}.column2This is what drives selection-aware buttons, counters and master/detail screens. Full examples: Verified examples, 6.5 and 6.6.
In such cases, do not guess. If table or dynamicPanel is used, consult:
When to avoid expression
- When the user only wants a static default text.
- When
defaultValueis sufficient. - When you only need to show or hide a section, not compute new data.
Final checklist
- Does the condition reference existing fields.
- Do boolean properties return a boolean value.
- Does
expressionnot return the wrong type. - Is there no self-reference.
- Is
logicExecutionMode: "onChange"added where needed.
