The art of hiding

14170
22
05-28-2016 02:27 AM
Esri Frequent Contributor
12 22 14.2K

This blog post is all about using the relevant column in your XLSForm to help you control the visibility of questionsSmaller.gif in your survey.  Mastering this is an important smart form design skill. A good smart form will never show end users a question unless it is necessary. The days where an endless collection of questions and data entry boxes are presented to the user should be over. The relevant column is present in the XLSForm survey worksheet and can optionally hold an expression. If the expression evaluates to true, the corresponding question will be shown. If the expression evaluates to false, it will be hidden. You can use data anywhere from your form as part of your expression, making your forms dynamically change based on the user's responses.

Lets go first through some examples:

Say you only want to ask a question if the response to a previous question is 'yes':

typenamelabelrelevant
select_one yes_noowner_presentIs the house owner present?
textowner_nameName:selected(${owner_name},'yes')

Other relevant expressions may include:

  • ${PreviousQuestion} < 18
  • int(${QuestionA})+ int(${QuestionB}) > 100
  • today() - ${LastInspectionDate} > 1000*60*60*24*15 (the last inspection happened more than 15 days ago)


The expression syntax uses the XLSForm specification. To learn more about how to write your own expressions check the Formulas—Survey123 for ArcGIS | Documentation help topic.

When using mathematical operators, one needs to be careful with empty responses. If a question has not been answered, it evaluates to 0. This would make for example ${PreviousQuestion} < 18 always return true, if ${PreviousQuestion} has not been answered.  To resolve this issue, you can add your expression to an if block as follows:

  • if (condition, a, b)  If the condition is met, returns a, otherwise returns b.
  • if(string-length(${PreviousQuestion}) = 0, false, ${PreviousQuestion} < 18)
  • if(string-length(${LastInspectionDate})=0, false, today() - ${LastInspectionDate} > 1000*60*60*24*15)

The safest way to check if a question has  been answered is using string-length(${QuestionName}).  If string-length returns 0, then you known the answer is empty. This function works well with question types of all sorts: with numbers, text, images, dates etc

In some cases, you may want to use regular expressions (regex) For example, the following expression can be used with a note type of question. If the expression evaluates to  true, the note is shown, otherwise it is hidden.

typenamelabelrelevant
textemailYour e-mail
noteType a correct e-mailregex(${Q2}, '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}')


A special case when using relevant statements are select_multiple questions. For them, the count-selected and selected statements are very handy. In the example below, the 'Select other topping:' question only appears if the choice 'Other' has been selected from the list of toppings.  The count-selected() function is used to display a 'Too many toppings' warning if more than 2 toppings have been selected.

typenamelabelrelevant
select_multiple toppingstoppingsPizza toppings
texttop_otherOther topping:selected(${toppings},'Other')
noteToo many toppings!count-selected(${toppings})>2

To learn more about select_multiple questions, have a look https://community.esri.com/groups/survey123/blog/2017/08/30/understanding-multiple-choice-questions-... 

Relevant expressions can be applied to many different types of questions: select_one, integer, text, image, barcode, repeat etc. You can also apply them to notes as well as to Groups and RepeatsGroups are of particular importance because a relevant statement applied to a Group will have effect over all questions within that Group.  If you have three or four questions to which you want to apply exactly the same relevant expression, you may want to consider creating a Group and apply the expression only to the Group. This will make your Survey load faster because you will be reducing the number of times the expression needs to be evaluated.

Another aspect to keep in mind is the effect relevant statements have on submit. If a question is not relevant (it is hidden), then data in that question will not be submitted to ArcGIS.

To learn more, check out the video tutorial below!


22 Comments
Occasional Contributor II

Hey @Ismael Chivite

How do I set a question to only appear if a previous question (of type select_one) is 'NOT BLANK' eg: the user has selected a value.

Thanks

Esri Frequent Contributor

${previousQuestion}!=''

Occasional Contributor

What if you wanted to evaluate multiple choices? I have tried something like selected(${multiSelect},'A,B') but doesn't work. 

Esri Esteemed Contributor

Hi Charles,

To do multiple, you need to group them in a compound statement:

selected(${multiSelect},'A') or selected(${multiSelect},'B')

Occasional Contributor

Thanks James, that works but it displays the relevant if 'A' or 'B' and any

other choices are selected. We's like it to specifically fire if 'A' or

'A,B' are selected, but no other combination. Is there a way to do that?

Having trouble getting an 'and' operator to work. Thanks again, cob

Occasional Contributor III

They're probably still having breakfast in Redlands, hope this helps:

Try: selected(${multiSelect},'A') or (selected(${multiSelect},'A') and selected(${multiSelect},'B'))

Occasional Contributor III

Ignore my previous post. After thinking about this again the relevant should probably look like this:

${multiSelect} = 'A' or ${multiSelect} ='A,B' or ${multiSelect} ='B,A'

The select multiple field populates in the order the options are selected so if 'B' was selected first the order of the answers would be "B,A". Knowing that users have a tendency to find exceptions to our logic I would add both permutations of an 'A,B' / 'B,A' combination.

Esri Esteemed Contributor

Update: I misread the requirement for evaluation, but will still keep this below to talk about negation

Brent's suggestion (which would also need or ${multiSelect} = 'B' ) is probably the shortest, unless there are sufficiently few choices that checking for the inverse (anything but A & B being selected) could also work (say we only have A,B,C,D as choices):

not(selected(${multiSelect}, 'C') or selected(${multiSelect}, 'D')) and count-selected(${multiSelect}) >= 1

Occasional Contributor

Brent, your second suggestion worked like a charm - what we needed was one

specific choice either by itself or in combination with one other specific

choice - this did the trick. Thanks, cob

Occasional Contributor

I'm fairly new to survey 123 so forgive me if this is an easy answer. 

I have 7 variables in a multiselect, call them A,B,C,D,E,F,G. i have a hidden text box that I would only like to appear if any combination of selections includes F or G. Example: A,B,C,F would make the textbox appear or  D,E,F,G. I really don't want to write out every combination, can you think of a way that I could do something like "multiselect includes F or G". 

Thanks,

Occasional Contributor

ended up answering my own question. I used a regEx. 

regex(${FIELD},'(F|G)') worked for me

Regular Contributor

It doesn't seem possible to evaluate different questions within the same relevant expression.

if((${Response}='Green Form'),True,if((${Leak_Response_Result}='Replaced'),True,False))

shows a text box when I first open the form. I thought that the False value would keep this box hidden unless one or the other previous questions were answered with the correct value.

While the above If statement passes the expression checker the following regex statement does not:

regex((${Response},'(Green Form)')|(${Leak_Response_Result},'(Replaced)'))

Esri Esteemed Contributor

Hi Mike,

The correct values for the if statements are true and false - note the lowercase.

Regex also would not be the best solution, as you're trying to match an exact value; to match one of two values you would need to use an or to join the separate comparisons:

${Response} = 'Green Form' or ${Leak_Response_Result} = 'Replaced'

New Contributor

Yes, it worked like a charm! Thank you.

MVP Regular Contributor

Is there an option to hide a repeat?

Occasional Contributor III

If I set up a field for dispatch how do I hide everything underneath until that dispatcher opens the form? Can it be done using a property("username")?

Esri Frequent Contributor

If you add property("username")='replacethiswithausername'  into the relevant field of a question, the question will only be shown when the indicated username is logged-in.

Occasional Contributor III

I'm having some issues using the property("username")='jnmiller@egas' multiple times for the relevant field. 

It works perfectly if I specify 1 user but as soon as I add more and use something like this it doesn't work: 

property("username")='jnmiller@egas' or property("username")='gkelly@egas

Maybe that function has a limit? Any ideas what could be causing this?

Esri Esteemed Contributor

Hi Jordan,

There shouldn't be a limit.  I am able to create a form with that pattern successfully:

New Contributor

Been trying to find a solution to this problem for awhile. Thank you! I don't wan't to type out every single combination.

Occasional Contributor III

Following...

I have two repeats, and I'd like the relevant option to show.

If not, I'll use compact in the appearance field.

New Contributor

James Tedrick I'm trying to set up a customized survey in the Conservation Easement Monitoring Solution.  I have two different surveys: one for easements and one for fee-owned properties.  Ideally the process would begin by selecting the property name, then based on the attribute "interest type" (easement or fee), the appropriate survey would be shown.  Any advice for a "conditional hide/show" type of formula based on the interest attribute?