A lot of users prefer to use numeric internal values for choice list options in multiple choice questions; it makes analysis, doing logic checks in the form, etc. easier. At the same time, you may wish to return and display a prior answer from a multiple choice question in a later question in your form design and this can pose a problem. Directly referring to the multiple choice question would display the internally stored numeric value rather than the label of the answer, which is more user readable.
Note: For anyone not comfortable writing expressions by hand, don't worry. Most of the expressions discussed in this guide can be built for you using the calculation expression wizard in the online form designer or the tools on the Design tab (Your forms and datasets > Tools > Build calculation).
The problem
For example, lets say a form design has a select_one field (q1) where the primary source of the respondent's income is asked and the answer choices use numeric codes. E.g. 1 = farming, 2 = small business, 3 = salaried job. The respondent selects 3, 'salaried job' as the answer.
And in the next question (q2) the user would like to ask "How much do you make each month from ${q1}?" and dynamically have the question text change to display the actual income source.
But simply referring to the multiple choice field directly - as I have done above - will display the actual answer stored in the field ${q1}, and so would appear as "How much do you make each month from 3?" rather than "How much do you make each month from salaried job?"
The solution
In order to display the label of the answer option rather than the answer option itself, one has to first use the choice-label()
function in a calculate field and then refer to this calculate field instead. The choice-label() function lets you pull the label associated with a particular answer value and store that label as a string. So, in the above example, after q1, I could create a calculate field and put the following as its calculation expression:
choice-label(${q1}, ${q1})
That will take the value stored in q1, and then pull the label associated with that value in the list of answer options for q1.
Then, for my question text in q2, I can put the following: "How much do you make each month from ${calcfieldname}?"
Now the question text will display the label, since that is now stored as a string in the calculate field.
Displaying select_multiple labels in your form
When you select multiple choices using a select_multiple field, the choice values are stored in a space-separated list. To display the labels of all selected choices, you can cycle through them using a repeat group, as demonstrated in the sample form in our documentation Follow-ups: Asking follow-up questions for a list of selected items. Methods 1 and 4 describe how to cycle through all selected choices. There, method 4 is described as the preferred method, but method 1 may be better for your workflow, and we will discuss both here.
Implement either method 1 or method 4 to gather the choice labels, and then follow the steps for Displaying the labels of the selected choices to actually display them using either the join() function or a repeat group.
The follow-ups sample form documentation also mentions three other methods: method 2 is the same as method 1 but for pre-loaded choice lists, and method 3 is the same as method 4 but for pre-loaded choice lists. If your choice lists are pre-loaded, you can still use the steps below, but adapt them for pre-loaded choice lists. Method 5 is not relevant here, since it uses a series of yes/no questions instead of a single select_multiple field. |
Method 1
This section is accompanied by this sample form.
In this method, we will add a field that counts the number of choices selected, use that as the repeat_count in a repeat group, and then use the repeat group to cycle through each selected choice, and retrieve each choice label of each selected choice. Those labels are later collected into a single field that lists all selected choice labels.
First, add a calculate field that counts the total number of choices selected. For example, if the select_multiple is called "crops_grown", then add a calculate field with this calculation:
count-selected(${crops_grown})
We will give that field the name "num_crops".
Next, add a repeat group to your form. For its repeat_count, use a field reference to the field "num_crops". That way, its repeat_count is based on the number of choices selected in the select_multiple field.
Within the repeat group, add a field that calculates the repeat index, and subtracts 1 (this is because repeat indexes start at 1, while list indexes start at 0):
index() - 1
We will call the calculate field with that calculation "crop_index".
Add another calculate field that uses the selected-at() function to retrieve each selected choice value. The field will be the select_multiple field "crops_grown", and the value will be the crop index:
selected-at(${crops_grown}, ${crop_index})
That way, the first repeat instance will retrieve the value of the first crop selected, the second repeat instance will retrieve the value of the second crop selected, and so on. We will call the field with that calculation "crop_value".
Finally, use that retrieved choice value with the choice-label() function to retrieve the choice label, like this:
choice-label(${crops_grown}, ${crop_value})
We will call the field with that calculation "crop_label".
Method 4
In this method, the repeat group will cycle through each choice value whether it was selected or not, but it will only retrieve the choice label if the choice was actually selected. This can prevent possible issues if the enumerator goes back and changes the choices selected.
For the choice list of the select_multiple field, make sure each choice value follows an arithmetic pattern (i.e. each numeric choice value increases by the same amount each time). For simplicity, it is a good idea to start at 1, and have each choice value increase by 1, e.g. 1, 2, 3, 4, etc, and we will use that in this example.
Add a repeat group with a repeat_count based on the total number of choices. For example, if your choice list has 4 choices total, then the repeat_count will simply be 4
.
In the repeat group, add a calculate field that simply stores the repeat index (no subtraction) with this calculation:
index()
That way, it cycles through every choice value, whether it was selected or not (i.e. the first instance will have a value of 1, corresponding to the first choice value; the second instance will have a value of 2, corresponding to the second choice value; etc). We will call the field with that calculation "crop_value".
If your choice values do not start at 1, or they do not increase by 1 each time, you will have to adjust the calculation of "crop_value". |
Within that repeat group, add a non-repeating group. Give that group a relevance expression so that it is only relevant when the crop value generated by "crop_value" has been selected:
selected(${crops_grown}, ${crop_value})
That way, if the crop was not selected, then it will skip over that instance of the group, and move on to the next one.
Within that regular group, add a calculate field that uses the crop value with the select_multiple field to retrieve the choice label. For example, if the select_multiple is called "crops_grown", use this calculation:
choice-label(${crops_grown}, ${crop_value})
We will call the field with that calculation "crop_label".
(For now, that regular group only has a single field, but we will discuss it more soon.)
Displaying the labels of the selected choices
Now that you have the choice labels, you can start displaying them in field labels. You can either display them all at once, or one-at-a-time.
All at once
To display them all at once, outside of the repeat group, simply add a calculate field that uses the join() function on the field that generates the choice labels, like this:
join(', ', ${crop_label})
That will create a list of all crop labels that were selected, separated by a comma-space. You can reference that field in field labels. If this is all you are doing, then method 1 will work well.
One-at-a-time
This section is accompanied by this sample form.
You can also display the choice labels one-at-a-time. Above, with method 4, we mentioned adding a regular group, which at the time, only had a single calculate field. Within that regular group, you can add visible fields that reference the field "crop_label", like this:
How many kilograms of ${crop_label} did you grow this year?
That way, each repeat instance will display the label of a different crop.
You can also use method 1 for this, but enumerators may run into issues if they go back and change which crops were selected. For example, if crops 1 and 3 were selected, and the enumerator enters 30 kilograms for crop 3, if they go back and select crop 2 as well, then that 30 kilograms will be shown for crop 2 instead, not crop 3. While not a major issue, to ensure there are as few errors and mistakes as possible, we recommend using method 4 when asking follow-up questions like this.
Intermediate: Displaying "other" text choices
If the enumerator selects "Other" in the select_multiple field, it is a good idea to add a text field where the enumerator can enter what that "Other" option is, as described in this support article. You can also display those "Other" choices to the enumerator later in the form. For sample forms demonstrating this, check out this folder (for help deploying the sample forms to your server, check out our support article Deploying form definitions).
Limitations
The choice-label()
function does have a limitation in the context of multilingual form designs. It does not readily re-evaluate in response to swapping languages while using the form. Expressions in general re-evaluate at different points (e.g. when fields upon which they depend change their values) but form logic is agnostic of which labels are being displayed at the time. As a result, if you are swapping between languages while testing a form, moving backward and forward, you might see labels from the wrong language returned. This limitation might make choice-label()
an unsuitable solution for multilingual data collection scenarios that require going backward in the form (e.g. when using non-linear form navigation). If form users are likely to stick to one language and have no reason to page back and swap languages, this limitation should not be cause for concern.
There are other methods for dynamically displaying pieces of text from different languages in a form design that don't have this limitation but they are a bit more work. The first, suitable if the choice list is not very long, would be to use a nested if()
expression in a calculate field per language to return the right label to display. Using the above example, this would look like this for English:
if(${q1} = 1, 'farming', if(${q1} = 2, 'small business', 'salaried job'))
In the above, if()
appears inside if()
which is possible to do, to get more than two outcomes. To extend, a.) add in new if()
conditions ("if(${field} = 'value',
'result if true', ..
"), b.) make sure that you add additional closing brackets at the end and c.) be sure that the "if false" condition returned at the end is accounted for in your logic. if()
expressions must be specified by hand.
Otherwise, you might pre-load label values from an attached data source per language using the pulldata()
function in a calculate field. This would look like this for English:
pulldata('income_source', 'english_label', 'id_key', '${q1})
Functions and operators referenced in this article: choice-label(), selected-at() if() and pulldata(). For a full list of SurveyCTO functions and operators, please read this help topic.
Do you have thoughts on this support article? We'd love to hear them! Feel free to fill out this feedback form.
0 Comments