Expressions
Learn how to use expressions.
Prerequisites:
@vueform/vueform
1.13.0
What Are Expressions?
Expressions let you display dynamic content based on form values. They're often called formulas or computed values.
You can use expressions:
- as the value of
TextElement
andHiddenElement
using theexpression
option - in the
content
option ofStaticElement
- in
conditions
,readonly
, anddisabled
options of any element
Using Expressions
The TextElement
and HiddenElement
has an expression
option that can include expressions between curly brackets {}
:
<TextElement
name="first_name"
label="First name"
default="John"
/>
<TextElement
name="greeting"
label="Greeting"
expression="Hi, {first_name}!"
readonly
/>
Expression Resolution Cycle
In the example above, the greeting
field uses an expression that references first_name
. Behind the scenes, this sets up a watcher on first_name
, so whenever first_name
changes, greeting
automatically updates its value.
This means that if you're listening to the @change
event on the Vueform
, you'll get two events:
- One when
first_name
changes - Another when
greeting
updates as a result
Now, if you add a third field that references greeting
in its expression, you'd get yet another update because that field only updates after greeting
changes.
This cascading effect is important to keep in mind when chaining expressions. Each dependent field triggers its own update, which can lead to multiple change events for a single user action.
Escaping Expressions
If you want to display curly brackets without triggering an expression, you can escape them with \
:
<TextElement
...
expression="Hi, \{first_name\}!"
/>
Nested Elements
To reference nested elements, use their dataPath
, not path
:
<GroupElement name="profile"> <!-- GroupElement DOESN'T nest data -->
<TextElement
name="first_name"
label="First name"
default="John"
/>
</GroupElement>
<ObjectElement name="address"> <!-- ObjectElement DOES nest data -->
<TextElement
name="zip"
label="ZIP Code"
default="MI 48105"
/>
</GroupElement>
<TextElement
name="greeting"
label="Greeting"
expression="Hi, {first_name}! You ZIP code is: {address.zip}"
readonly
/>
Array Values
You can access array values using dot notation with the index:
<TagsElement
name="options"
label="Options"
:items="['Option 1', 'Option 2', 'Option 3']"
:default="['Option 2', 'Option 3']"
/>
<TextElement
name="first"
label="First option"
expression="First option: {options.0}"
readonly
/>
Object Values
You can access object properties directly as well:
<ListElement
name="users"
label="Users"
label-prop="name"
:object="true"
:native="false"
:items="[
{id: 123, name: 'John', role: 'admin'},
{id: 456, name: 'Jane', role: 'editor'}
]"
:default="{id: 123, name: 'John', role: 'admin'}"
/>
<TextElement
name="role"
label="Role"
expression="{user.role}"
readonly
/>
Sibling Values
To reference sibling values in a list, use *
instead of a specific index:
<SelectElement
name="user"
label="User"
:element="{
type: 'object',
schema: {
id: { type: 'text', placeholder: 'ID' },
name: { type: 'text', placeholder: 'Name' },
role: { type: 'select', placeholder: 'Role', items: ['admin', 'editor'] },
key: { type: 'text', placeholder: 'Key', expression: '{user.*.role}-{user.*.id}', disabled: true }
}
}"
:default="[
{
id: 123,
name: 'John',
role: 'admin',
}
]"
/>
Math Expressions
You can do calculations and use opreators inside expressions:
<TextElement
name="qty"
label="Quantity"
input-type="number"
default="5"
/>
<TextElement
name="price"
label="Price"
input-type="number"
default="10"
/>
<TextElement
name="total"
label="Total"
expression="{ qty * price }"
readonly
/>
Using Functions
You can also call built-in functions:
<DateElement
name="dob"
label="Date of birth"
default="1989-07-07"
/>
<TextElement
name="age"
label="Age"
expression="{AGE(dob)}"
readonly
/>
You can also add your custom functions.
Using Logical Expressions
Use ternary expressions for conditional values:
<DateElement
name="dob"
label="Date of birth"
default="1989-07-07"
/>
<TextElement
name="allowed"
label="Allowed"
expression="{AGE(dob) > 18 ? 'allowed' : 'not_allowed'}"
readonly
/>
Using Expressions in StaticElement
Expressions in StaticElement
's content
option require enabling the expressions
first:
<TextElement
name="first_name"
label="First name"
default="John"
/>
<StaticElement
name="greeting_1"
label="Greeting"
content="Hi, {first_name}!"
/>
<StaticElement
name="greeting_2"
label="Greeting"
content="Hi, {first_name}!"
:expressions="true"
/>
Using Expressions in Conditions-like Options
When using expressions in conditions
, disabled
or readonly
, pass them as plain strings—without {}
:
<CheckboxElement
name="create_account"
text="I want to create an account"
/>
<TextElement
name="password"
input-type="password"
label="Password"
:conditions="[
'create_account == true'
]"
/>
When expressions are used in condition-like options, they should not be wrapped in {}
and they always must end up having a logical value (true
or false
).
Invalid expressions and expressions that don't return a logical value will resolve as an unmet condition.
You can combine expressions with AND
-type conditions, but not OR
:
<DateElement
name="birthday"
label="Birthday"
default="1960-06-12"
/>
<CheckboxElement
name="create_account"
text="I want to create an account"
/>
<!-- This WILL work -->
<TextElement
name="password"
input-type="password"
label="Password"
:conditions="[
// `AND` type conditions
'AGE(birthday) > 18',
['create_account', true],
]"
/>
<!-- This WON'T work -->
<ButtonElement
name="button"
button-label="Create account"
:conditions="[
// `OR` type conditions
[
'AGE(birthday) > 18',
],
[
['create_account, true],
]
]"
/>
In general it's advisable to use a single condition if you are using expressions.
Operators
Operator | Description | Example |
---|---|---|
+ | Adds two numbers together. | {subtotal + tax} |
- | Subtracts the right number from the left number. | {total - discount} |
* | Multiplies two numbers. | {price * quantity} |
/ | Divides the left number by the right number. | {total / count} |
% | Returns the remainder after division of the left number by the right number. | {count % 2} |
^ | Raises the left number to the power of the right number. | {base ^ exponent} |
! | Factorial of the number. Multiplies all whole numbers from the number down to 1. | {5!} |
== | Checks if the value on the left is equal to the value on the right. | {category == 'main'} |
!= | Checks if the value on the left is not equal to the value on the right. | {category != 'main'} |
>= | Checks if the value on the left is greater than or equal to the value on the right. | {price >= 100} |
> | Checks if the value on the left is greater than the value on the right. | {price > 100} |
<= | Checks if the value on the left is less than or equal to the value on the right. | {price <= 100} |
< | Checks if the value on the left is less than the value on the right. | {price < 100} |
in | Checks if the value on the left exists in the array or object on the right. | {'admin' in roles} |
() | Groups expressions to control order of evaluation. | {(price > 100) and (stock > 0)} |
and | Returns true if both expressions are true . | {is_active and is_verified} |
or | Returns true if at least one expression is true . | {is_admin or is_moderator} |
Functions
NOT(value)
- Arguments:
{string} value*
- An expression or reference to an element holding an expression that represents some logical value, i.e.true
orfalse
- Returns:
boolean
EMPTY(value)
- Arguments:
{string} value*
- The value or expression to check — can be a string or array.
- Returns:
boolean
NOT_EMPTY(value)
- Arguments:
{string} value*
- The value or expression to check — can be a string or array.
- Returns:
boolean
SUM(value1, [value2, ...])
- Arguments:
{string} value1*
- The first number or list of numbers to add together.{string} value2
- Additional numbers or lists to add to the total.
- Returns:
number
AVG(value1, [value2, ...])
- Arguments:
{string} value1*
- The first number or list of numbers to average.{string} value2
- Additional numbers or lists to include in the average.
- Returns:
number
MIN(value1, [value2, ...])
- Arguments:
{string} value1*
- The first number or list of numbers to check.{string} value2
- Additional numbers or lists to check.
- Returns:
number
MAX(value1, [value2, ...])
- Arguments:
{string} value1*
- The first number or list of numbers to check.{string} value2
- Additional numbers or lists to check.
- Returns:
number
ROUND(number, [places])
- Arguments:
{string} number*
- The number to round.{string} places
- Number of decimal places to round to. Defaults to 0.
- Returns:
number
COUNT(value1, [value2, ...])
- Arguments:
{string} value1*
- A single value or an array to count.{string} value2
- Additional values or arrays to include in the count.
- Returns:
number
AGE(birthday)
- Arguments:
{string} birthday*
- Date of birth as a string or date value.
- Returns:
number
TODAY()
- Returns:
string
NOW()
- Returns:
string
DATE_ADD(date, to_add, interval)
- Arguments:
{string} date*
- The starting date.{string} to_add*
- The number of intervals to add (can be negative).{string} interval*
- The type of interval:seconds
,minutes
,hours
,days
,months
,years
.
- Returns:
string
FORMAT_DATE(value, format)
- Arguments:
{string} value*
- A string or number representing a date.{string} format*
- The format the date should have. Formatting tokens
- Returns:
string
DISPLAY_VALUE(value, 'full_path')
- Arguments:
- Returns:
string
Constants
PI
E
Adding Custom Functions and Constants
We can add custom functions and contants in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
expression: {
functions: {
CUSTOM_FUNC(arg1, arg2, ...) {
return 'return value'
}
},
consts: {
CUSTOM_CONST: 'const value',
}
},
})
Debugging
To debug expressions enable expressionDebug
in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
expressionDebug: true // `false` by default
})