Form logic
Form Descriptors has a powerful syntax to create dynamic logic. You can use it to:
- Show or hide fields based on other fields
- Disable or make a field readonly based on other fields
- Change the design of a component based on other fields
- Use the value of one field in the label or help-text of another field
- Create a dynamic html block that summarize the form values
Example
Let's start with an example to make it more clear:
type text
name full_name
label Full Name
placeholder Jane Smith
validations required
type email
name email
label What is your email address{% if name %}, {{full_name}}{% endif %}?
placeholder jane@example.com
validations required|email
This form defined a full_name
and email
fields. The label of the email field is personalized using the value provided by the user in the name field. If the user provided the name Alexander
, then the label of the email field will be What is your email address, Alexander?
.
The variable full_name
corresponds to the name
property of the first input field. When you write your logic, you can use any input field's name
property as a variable.
You may wonder what is the difference between {% %}
and {{ }}
. The first one is a Tag that performs an operation, and the second one is an Expression that returns a value. You can see how they work in the following sections.
Tags
Tags are special blocks that perform operations on sections of the template. Supported tags are
if
Conditional blocks
{% if condition %}anything here will be output if the condition is true{% endif %}
for
Iterate over arrays and dictionaries
{% for item in items %}
<li>{{ item }}</li>
{% else %}
<li>This would display if the 'item' collection were empty</li>
{% endfor %}
filter
Performs one or more filters (transformations) on the content of the block. See list of available filters here
{% filter upper %}This text will be uppercase{% endfilter %}
- raw - if you want to output any special text such as
{{
or{%
as is, you can use the raw tag{% raw %}this text {{ will be shown %} as-is{% endraw %}
Expressions
Expressions return a value that is being output. Here are some examples:
{{ full_name }}
- returns the value of the field with the namefull_name
{{ 3 + 5 }}
- returns 8{{ number_field > 8 }}
- returns true if the value ofnumber_field
is larger than8
Here's a full list of supported expression operators:
Math operations
- Addition:
+
- Subtraction:
-
- Division:
/
- Division and integer truncation:
//
- Division remainder:
%
- Multiplication:
*
- Power:
**
Comparisons
==
- Equals. Similar to Javascript, using this operatorfalse
,0
,""
(empty string),[]
(empty array) andundefined
- are all equal to each other. Also, the number5
and the string"5"
will be equal. For most practical uses, this is the equality that you want to use.===
- Strictly equals. Similar to Javascript, two values are strictly equal only if they have the exact same value.!=
- Not equals.!==
- Strictly not equals.>
- Greater than.>=
- Greater than or equals.<
- less than.<=
- less than or equals.
Logic
and
or
not
You can use parentheses to group expressions. E.g.
{{ (number > 5 and another_number < 2) or number > 10 }}
If expression
If expression are similar to javascript's ternary operator. They use the following syntax:
{{ true_value if condition else false_value }}
If condition
has a truthy value, then true_value
is returned. Otherwise, false_value
is returned.
if
expressions can also skip the else
part, and then they will not output anything if the condition isn't met.
{{ true_value if condition }}
The following example will add the class text-green-500
to the header, only if the field full_name
has a value:
type h1
text Contact us
attributes
class {{ "text-green-500" if full_name }}
Regular expressions
A regular expression can be created just like JavaScript, but needs to be prefixed with r
. The following example adds the help text You are the one!
if the user provides the name Neo
:
type text
name name
label Name
help {% set regExp = r/Neo/ %}{{ "You are the one!" if regExp.test(name)}}
placeholder John Doe
validations required
Functions
You can call the following functions, just as you would in Javascript
range([start], stop, [step])
If you need to iterate over a fixed set of numbers, range
generates the set for you. The numbers begin at start
(default 0
) and increment by step
(default 1
) until it reaches stop
, not including it.
{% for i in range(0, 5) -%}
{{ i }}
{%- endfor %}
This will output 01234
Note: the
-
(minus) sign at the end and beginning of the tags (-%}
and{%-
) tells the engine to strip down any spaces coming right after or before the closing or opening tag, respectively. Without it, the above would output0 1 2 3 4
, because the line that printsi
has 2 spaces before the expression{{ i }}
, and one right after it.
cycler(item1, item2, ...itemN)
An easy way to rotate through several values is to use cycler
, which takes any number of arguments and cycles through them.
{% set cls = cycler("text-green-500", "text-blue-500") %}
{% for name in names %}
<div class="{{ cls.next() }}">{{ name }}</div>
{% endfor %}
joiner([separator])
When combining multiple items, it's common to want to delimit them with something like a comma, but you don't want to output the separator for the first item. The joiner
class will output separator
(default ,
) whenever it is called, except for the first time.
{% set comma = joiner() %}
{% for tag in tags -%}
{{ comma() }} {{ tag }}
{%- endfor %}
If tags
was ["food", "beer", "dessert"]
, the above example would output food, beer, dessert
.
Comments
You can write comments using {#
and #}
. Anything inside will be stripped out.
Filters
Filters (also called transformations) can be applied on any value in order to modify it. Multiple filters can be chained using |
The following filters are available
abs
Return the absolute value of the argument
{{ -3|abs }}
Outputs 3
capitalize
Make the first letter uppercase, the rest lower case
{{ "This Is A Test" | capitalize }}
Outputs This is a test
default(default_value, [boolean])
If the input is undefined
, returns default_value
, otherwise it returns the input. If boolean
is true, any JavaScript falsy value (false
, ""
, []
, 0
, etc.) will return default_value
{{ name | default('John', true }}
Outputs John
if name
is undefined, or the value of name
if it is defined.
Note: the initial value of most fields will be undefined. However, if the user provides a value and then deletes it, the value is defined, but it equals to the empty string
""
. Therefore, if you wantdefault
to work consistently, you should providetrue
as the second parameter.
escape
Converts the characters &
, <
, >
, ‘
, and ”
to HTML-safe sequences. Use this if you need to display text that might contain such characters in a html block.
Note: This filter is only needed in html blocks, because they output html code as-is. Labels, help-text, placeholders, and any other block properties are escaped by default, so there's no need to use this filter on them.
{{ "<html>" | escape }}
Outputs <html>
first
Gets the first item in an array or the first letter of a string.
{% set items = [1,2,3] %}
{{ items | first }}
{% set word = 'abc' %}
{{ word | first }}
Outputs
1
a
float([default])
Converts a string to a floating point number. If the conversion fails returns default
or nothing if default
isn't provided.
{{ "3.5" + 2 }}
{{ "3.5" | float + 2 }}
outputs
3.52
5.5
groupby(attribute)
Group a sequence of objects by a common attribute
. Attribute can use dot notation to use nested attribute, like date.year
.
{% set items = [
{ name: 'james', type: 'green' },
{ name: 'john', type: 'blue' },
{ name: 'jim', type: 'blue' },
{ name: 'jessie', type: 'green' }
]
%}
{% for type, items in items | groupby("type") %}
<b>{{ type }}</b> :
{% for item in items %}
{{ item.name }}
{% endfor %}<br>
{% endfor %}
Outputs
green : james jessie
blue : john jim
int([default])
Converts a string to an integer. If the conversion fails returns default
or nothing if default
isn't provided.
{{ "3.5" + 2 }}
{{ "3.5" | int + 2 }}
outputs
3.52
5
join([separator], [selector])
Concatenates strings in a sequence.
- The
separator
between elements is an empty string by default, and it can be defined with an optional parameter. - If the array is array of objects, the second parameter can be used to property of each item that will be picked
{% set items = [
{ name: 'foo' },
{ name: 'bar' },
{ name: 'bear' }]
%}
{{ items | join(",", "name") }}
Outputs foo,bar,bear
last
Get the last item in an array or the last letter if it's a string.
{% set items = [1,2,3] %}
{{ items | last }}
{% set word = 'abc' %}
{{ word | last }}
Outputs
3
c
length
Return the length of an array or string, or the number of keys in an object.
{{ [1,2,3] | length }}
{{ "test" | length }}
{{ {key: value} | length }}
Outputs
3
4
1
lower
Convert string to all lower case.
{{ "fOObAr" | lower }}
Outputs foobar
nl2br
Replace new lines with <br />
HTML elements. Useful, for example, if you want to print the value of a textarea fields in an html block.
{{ "foo\nbar" | escape | nl2br }}
Outputs foo<br />\nbar
random
Select a random value from an array.
{{ [1,2,3,4,5,6,7,8,9] | random }}
Outputs a random value between 1-9.
reject
Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
{% set numbers=[0, 1, 2, 3, 4, 5] %}
{{ numbers | reject("odd") | join }}
{{ numbers | reject("even") | join }}
{{ numbers | reject("divisibleby", 3) | join }}
{{ numbers | reject() | join }}
Outputs
024
135
1245
0
rejectattr(property)
Same as reject
, but works on array of objects and test the value of the selected property
.
{% set foods = [{tasty: true}, {tasty: false}, {tasty: true}]%}
{{ foods | rejectattr("tasty") | length }}
Outputs 1
replace
Replace one item with another. The first item is the item to be replaced, the second item is the replaced value.
{% set numbers = 123456 %}
{{ numbers | replace("4", ".") }}
Outputs 123.56
reverse
Reverse a string.
{{ "abcdef" | reverse }}
Outputs fedcba
round([digits])
Rounds a number. You can specify number of digits
to leave after the decimal point.
{{ 4.5 | round }}
{{ 4.12346 | round(4) }}
Outputs
4
4.1235
select
Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding. The opposite of reject
.
If no test is specified, each object will be evaluated as a boolean.
{% set numbers=[0, 1, 2, 3, 4, 5] %}
{{ numbers | select("odd") | join }}
{{ numbers | select("even") | join }}
{{ numbers | select("divisibleby", 3) | join }}
{{ numbers | select() | join }}
Outputs
135
024
03
12345
selectattr(property
)
Same as select
, but works on array of objects and test the value of the selected property.
{% set foods = [{tasty: true}, {tasty: false}, {tasty: true}]%}
{{ foods | selectattr("tasty") | length }}
Outputs 2
sort(arr, reverse, caseSens, attr)
Sort arr. If reverse
is true, result will be reversed. Sort is case-insensitive by default, but setting caseSens
to true
makes it case-sensitive. If attr
is passed, will compare attr
from each item.
{% set posts = [
{ title: "Banana" },
{ title: "apple" },
{ title: "Cherry" }
] %}
{% for post in posts | sort(false, false, 'title') %}
{{ post.title }}
{% endfor %}
Outputs
apple
Banana
Cherry
string
Convert an object to a string.
{{ 1234 | string | list | join("|") }}
Outputs 1|2|3|4
sum
Output the sum of items in the array.
{{ [1,2,3] | sum }}
Outputs 6
title
Turns first letter of each word to uppercase
{{ "foo bar baz" | title }}
Outputs Foo Bar Baz
trim
Strip leading and trailing whitespace.
{{ " foo " | trim }}
Outputs foo
truncate
Return a truncated copy of the string. The length is specified with the first parameter which defaults to 255
. If the second parameter is true
the filter will cut the text at length. Otherwise, it will discard the last truncated word. If the text was in fact truncated it will append an ellipsis sign ("..."), or the string provided by the third parameter.
{{ "foo bar" | truncate(5, true, "") }}
{{ "foo bar" | truncate(5) }}
Outputs
foo b
foo...
upper
Convert the string to upper case.
{{ "foo" | upper }}
Outputs FOO
wordcount
Count and output the number of words in a string.
{{ "hello world" | wordcount }}
Outputs 2