You can use expressions in a survey to control the default behavior of questions. A question, or a group of questions, can be hidden and revealed based on previous answers using expressions in the relevant column. When a question is hidden through an expression in the relevant column, no data is submitted for the question.
Note:
In Survey123 Mobile and the field app, if an answer is entered for a question that is later hidden because of a relevant expression, the answer is cleared. If the question becomes relevant again, a new answer must be entered. In the web app, the answer is not cleared, so if the question becomes relevant again, the previously entered answer is used.
You can also apply expressions to the readonly column, which can disable input to a question or group based on the result of the expression. The required column also supports expressions, allowing the survey to require the user to answer a question only under specific conditions.
Note:
Read-only expressions are not supported in the web app.
Previous questions must always be referred to in expressions with the format ${field_name}.
Question visibility
You can hide a question from view with an expression using the body::esri:visible column. This column hides the question if the expression it contains does not evaluate as true, while still keeping the contents of the question. For example, the expression ${edit_location}='yes' causes the question to only display if the edit_location question is equal to yes.
This behavior is similar to the relevant column, with both columns hiding a question until the expression in the column evaluates as true. The primary difference is that body::esri:visible doesn't clear the value of a question that is made not visible by the expression, and submits existing values to the feature layer. Use the relevant column instead of body::esri:visible when you want to ensure that the question will have no values calculated or stored when it is not relevant.
When using either the body::esri:visible or relevant columns to control question visibility, required, defaults, constraints, and input masks are only enforced when the question is visible.
You can also control the visibility of questions using the hidden question type and the hidden appearance, but these cannot be controlled with an expression.
Note:
Image, audio, and file questions do not support being hidden by the body::esri:visible column.
Simple expressions
The best way to use one of these expressions is to change the behavior or visibility of the question, unless a particular answer was given previously. For example, the following expression checks if the answer to the previous question is true:
${previous_question} = 'true'
The following example checks if the answer to the previous question was greater than or equal to 100:
${previous_question} < 100
The select_multiple question type holds values differently than other question types, with each checked answer entered in the order it was selected, separated by commas. For example, selecting answers A and B, in that order, will present the response as A,B. To use a select_multiple question as part of an expression, you must use the selected function. The following example checks if the user answered the previous question with A and works regardless of other answers chosen:
selected(${previous_question}, 'A')
The count-selected function counts the number of options that have been selected in a select_multiple question and provides a number to use as an operator. The following example checks if the previous question had more than two choices selected:
count-selected(${previous_question}) > 2
You can use the count-selected function as a constraint for image or file questions with the multiline appearance to control the number of files submitted.
Mathematical expressions
The following example combines multiple operators and questions:
${previous_question} + ${other_previous_question} <= 100
When using mathematical operators, you may need to cast values into numbers. In the previous example, it is assumed that previous_question and other_previous_question are integers or decimals, but if the question types are strings, cast them as follows:
int(${previous_question}) + int(${other_previous_question}) <= 100
You can also perform mathematical expressions on date questions, which are saved as Epoch time, the amount of milliseconds passed since January 1, 1970. The following expression reveals a question only if the answer to the previous question is more than two weeks before today:
if( ${previous_question}='',false,today() - ${previous_question} > 1000*60*60*24*15)
Regular expressions
A regular expression is a sequence of characters used to match patterns in strings. In Survey123, if the pattern is matched, the expression will return true; otherwise, if the pattern is not matched, the expression will return false.
A regular expression can be built from the subexpressions listed in the following table:
| Subexpression | Match |
|---|---|
| ^ | Matches the beginning of the line. |
| $ | Matches the end of the line. |
| . | Matches any single character except a newline. |
| [...] | Matches any single character in brackets. |
| [^...] | Matches any single character not in brackets. |
| (re) | Groups regular expressions and remembers matched text. |
| (?: re) | Groups regular expressions without remembering matched text. |
| a| b | Matches either a or b. |
| \A | Beginning of the entire string. |
| \b | Matches word boundaries when outside brackets, and matches backspace (0x08) when inside brackets. |
| \B | Matches nonword boundaries. |
| \d | Matches digits. It is equivalent to [0 through 9]. |
| \D | Matches nondigits. |
| \G | Matches the point where the last match finished. |
| \n, \t, \e, and so on | Matches a new line, tab, escape, and so on. |
| \N | Back reference to capture group number N. |
| re* | Matches 0 or more occurrences of the preceding expression. |
| re+ | Matches 1 or more occurrences of the preceding expression. |
| re? | Matches 0 or 1 occurrences of the preceding expression. |
| re{ n} | Matches the exact number of occurrences of the previous expression defined in place of n. |
| re{ n,} | Matches n or more occurrences of the preceding expression. |
| re{ n, m} | Matches at least the number of occurrences defined by n and, at most, defined by m in the preceding expression. |
| \s | Matches a whitespace character: tab, line feed, form feed, carriage return, or space. |
| \S | Matches nonwhitespace. |
| \w | Matches word characters. |
| \W | Matches nonword characters. |
| \z | End of the entire string. |
| \Z | End of the entire string except allowable final line terminator. |
You can use regular expressions in any column that accepts expressions to alter the behavior of a question, unless the string provided by another question is in a given format. The following example, when placed in the relevant column, only displays a question if another question has been answered with a letter:
regex(${question},'[A-Za-z]')
The following example, when placed in the choice_filter column of a select_one question for street names, will only show choices of streets that are contained within the citystreets list that match the city name selected in a previous question named city:
regex(citystreets,${city})
For more examples of how to use a regular expression to add a constraint to a survey question, see Formulas.
Conditional expressions
A conditional expression is used to determine whether a statement (condition) returns true or false, and to return a nominated value for each case as follows:
if(condition, value if true, value if false)
In the example below, if the response to question_one is yes, the answer to the current question is also yes. If the response to question_one is not yes, the answer to the current question is no:
if(selected(${question_one}, 'yes'), 'yes', 'no')
Two questions can be used in a condition. In the following example, if the answer to both question_one and question_two is yes, the answer to the current question is also yes:
if(selected(${question_one}, 'yes') and selected(${question_two}, 'yes'), 'yes', 'no')
In the following example, if the answer to question_one or question_two is yes, the answer to the current question is also yes:
if(selected(${question_one}, 'yes') or selected(${question_two}, 'yes'), 'yes', 'no')
Conditional expressions can also be nested, but it is important to always include both a value for the true and false cases. In the example below, if the answer to question_one is not yes, question_two is assessed. If question_two is also not yes, question_three is assessed. If the responses to question_one, question_two, and question_three are all not yes, the answer to the question that uses this statement will be no.
if(selected(${question_one}, 'yes'), 'yes', if(selected(${question_two}, 'yes'), 'yes', if(selected(${question_three}, 'yes'), 'yes', 'no')))