-
Notifications
You must be signed in to change notification settings - Fork 47
[Developers] Beiwe skip logic spec
Documentation of the current front-end code
This needs a few new features in the survey editor interface:
-
Each question can have attached to it a conditional statement about whether to display the question
-
Every question in the survey should have a visible number (starting from Q1, as in Q1, Q2, etc.) in the UI so that the user can reference that question in conditional logic statements. When a user re-orders, deletes, adds, etc. a question, the randomly-generated
question_id
s don't change, but thequestion_id
s are invisible to the user; the visible question numbers in the UI should change automatically. -
The logic inside a conditional can reference the value of the answer to any previous question in the survey.
- Conditional logic should reference other questions by the unique IDs of those questions, but the user won't know that; the user will only see the visible question number.
- So when the user edits the conditional logic attached to Question 5 in the survey, the user should see an HTML select/dropdown menu offering Q1, Q2, Q3, or Q4. But if the user selects Q4, what gets written into the JSON is the unique
question_id
of Q4. - And if after choosing Q4 in for the conditional logic statement, the user deletes Q2 from the survey, then the conditional logic statement automatically updates to say that it's based on Q3 (because the
question_id
of that question hasn't changed.
- So when the user edits the conditional logic attached to Question 5 in the survey, the user should see an HTML select/dropdown menu offering Q1, Q2, Q3, or Q4. But if the user selects Q4, what gets written into the JSON is the unique
- Conditional logic should reference other questions by the unique IDs of those questions, but the user won't know that; the user will only see the visible question number.
-
Conditional logic does not need to take into account any information outside the current survey. The only variables it can use are the answers to previous questions in the current survey.
-
Conditional logic can only operate on answers with numeric values, i.e., the answers to
slider
,free_response
:NUMERIC
, andradio_button
questions. You don't need to enforce this restriction in the UI, but if it's relatively easy to build something enforcing that restriction, go ahead and do it.-
radio_button
questions don't have numeric answers, but we're going to give the answer options numeric values. You don't need to make any JSON spec changes to reflect this; we'll just assume that the first answer choice has value 0, the second choice has value 1, and so on. Please make a UI change reflecting this, though: in theradio_button
question modal, the answer options should have numbers 0, 1, 2, etc. displayed next to them. It's fine if bothradio_button
andcheckbox
questions have numbers next to the answer options (even though logical statements shouldn't be able to operate on checkbox answers); that's probably marginally easier to implement.
-
-
The logic inside a conditional can include multiple logical expressions connected by
AND
and/orOR
operators. -
Besides
AND
andOR
, we only need to support 5 logical operators:==
,<
,<=
,>
,>=
. As long as we're only doing numeric operations, it's not necessary to support theNOT
operator. -
Each logical expression with one of the
==
,<
,<=
,>
,>=
operators can take only two operands. A logical expression withAND
orOR
can take one or more operands.
The only change to the previous survey JSON spec is that each question object now has an optional attribute display_if
.
-
If a question does not have a
display_if
attribute, always display that question. -
If the
display_if
logical expression evaluates as True, display the question. If it evaluates as False, skip to the next question. -
The operators
==
,<
,<=
,>
,>=
take a list of two objects: the first object goes in front of the operator, and the second object goes after it. So{'>': [2, 1]}
encodes the expression2 > 1
. -
The operators
and
andor
take a list of any number of objects.{'and': [ {'>': [2, 1]}, {'==': [5, 6]}, {'<=': [0, 1]} ]}
encodes the expression(2 > 1) AND (5 == 6) AND (0 <= 1)
. -
A string references a question by its unique ID.
{'>': ['6695d6c4-916b-4225-8688-89b6089a24d1', 0]}
encodes the expression([answer to Question with ID '6695d6c4-916b-4225-8688-89b6089a24d1'] > 0)
-
If a logical expression references a question that wasn't answered, treat that expression as False. For example, if you're evaluating
(Q3 < 1) AND (4 > 3)
and Q3 wasn't answered (it'sNull
/None
/nil
etc.), it should evaluate as(False) AND (4 > 3)
. -
Question randomization overrides skip logic; if
survey.settings.randomize == 'True'
, ignore thedisplay_if
attributes.
{
'content': [
{'answers': [
{'text': 'Never'},
{'text': 'Rarely'},
{'text': 'Occasionally'},
{'text': 'Frequently'},
{'text': 'Almost Constantly'}],
'question_id': '6695d6c4-916b-4225-8688-89b6089a24d1',
'question_text': 'In the last 7 days, how OFTEN did you EAT BROCCOLI?',
'question_type': 'radio_button'},
{'answers': [
{'text': 'None'},
{'text': 'Mild'},
{'text': 'Moderate'},
{'text': 'Severe'},
{'text': 'Very Severe'}],
'display_if': {'>': ['6695d6c4-916b-4225-8688-89b6089a24d1', 0]},
'question_id': '41d54793-dc4d-48d9-f370-4329a7bc6960',
'question_text': 'In the last 7 days, what was the SEVERITY of your CRAVING FOR BROCCOLI?',
'question_type': 'radio_button'},
{'answers': [
{'text': 'Not at all'},
{'text': 'A little bit'},
{'text': 'Somewhat'},
{'text': 'Quite a bit'},
{'text': 'Very much'}],
'display_if': {'and': [
{'>': ['6695d6c4-916b-4225-8688-89b6089a24d1', 0]},
{'>': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 0]}
]},
'question_id': '5cfa06ad-d907-4ba7-a66a-d68ea3c89fba',
'question_text': 'In the last 7 days, how much did your CRAVING FOR BROCCOLI INTERFERE with your usual or daily activities, (e.g. eating cauliflower)?',
'question_type': 'radio_button'},
{'display_if': {'or': [
{'and': [
{'<=': ['6695d6c4-916b-4225-8688-89b6089a24d1', 3]},
{'==': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 2]},
{'<': ['5cfa06ad-d907-4ba7-a66a-d68ea3c89fba', 3]}
]},
{'and': [
{'<=': ['6695d6c4-916b-4225-8688-89b6089a24d1', 3]},
{'<': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 3]},
{'==': ['5cfa06ad-d907-4ba7-a66a-d68ea3c89fba', 2]}
]},
{'and': [
{'==': ['6695d6c4-916b-4225-8688-89b6089a24d1', 4]},
{'<=': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 1]},
{'<=': ['5cfa06ad-d907-4ba7-a66a-d68ea3c89fba', 1]}
]},
]},
'question_id': '9d7f737d-ef55-4231-e901-b3b68ca74190',
'question_text': "While broccoli is a nutritious and healthful food, it's important to recognize that craving too much broccoli can have adverse consequences on your health. If in a single day you find yourself eating broccoli steamed, stir-fried, and raw with a 'vegetable dip', you may be a broccoli addict. This is an additional paragraph (following a double newline) warning you about the dangers of broccoli consumption.",
'question_type': 'info_text_box'},
{'display_if': {'or': [
{'and': [
{'==': ['6695d6c4-916b-4225-8688-89b6089a24d1', 4]},
{'or': [
{'>=': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 2]},
{'>=': ['5cfa06ad-d907-4ba7-a66a-d68ea3c89fba', 2]}
]}
]},
{'or': [
{'>=': ['41d54793-dc4d-48d9-f370-4329a7bc6960', 3]},
{'>=': ['5cfa06ad-d907-4ba7-a66a-d68ea3c89fba', 3]}
]}
]},
'question_id': '59f05c45-df67-40ed-a299-8796118ad173',
'question_text': 'OK, it sounds like your broccoli habit is getting out of hand. Please call your clinician immediately.',
'question_type': 'info_text_box'},
{'question_id': '9745551b-a0f8-4eec-9205-9e0154637513',
'question_text': 'How many pounds of broccoli per day could a woodchuck chuck if a woodchuck could chuck broccoli?',
'question_type': 'free_response',
'text_field_type': 'NUMERIC'},
{'display_if': {'<': ['9745551b-a0f8-4eec-9205-9e0154637513', 10]},
'question_id': 'cedef218-e1ec-46d3-d8be-e30cb0b2d3aa',
'question_text': 'That seems a little low.',
'question_type': 'info_text_box'},
{'display_if': {'==': ['9745551b-a0f8-4eec-9205-9e0154637513', 10]},
'question_id': '64a2a19b-c3d0-4d6e-9c0d-06089fd00424',
'question_text': 'That sounds about right.',
'question_type': 'info_text_box'},
{'display_if': {'>': ['9745551b-a0f8-4eec-9205-9e0154637513', 10]},
'question_id': '166d74ea-af32-487c-96d6-da8d63cfd368',
'question_text': "What?! No way- that's way too high!",
'question_type': 'info_text_box'},
{'max': '5',
'min': '1',
'question_id': '059e2f4a-562a-498e-d5f3-f59a2b2a5a5b',
'question_text': 'On a scale of 1 (awful) to 5 (delicious) stars, how would you rate your dinner at Chez Broccoli Restaurant?',
'question_type': 'slider'},
{'display_if': {'>=': ['059e2f4a-562a-498e-d5f3-f59a2b2a5a5b', 4]},
'question_id': '6dd9b20b-9dfc-4ec9-cd29-1b82b330b463',
'question_text': 'Wow, you are a true broccoli fan.',
'question_type': 'info_text_box'},
{'question_id': 'ec0173c9-ac8d-449d-d11d-1d8e596b4ec9',
'question_text': 'THE END. This survey is over.',
'question_type': 'info_text_box'}],
'settings': {'number_of_random_questions': None,
'randomize': False,
'randomize_with_memory': False,
'trigger_on_first_download': False},
'survey_type': 'tracking_survey',
'timings': [[], [67500], [], [], [], [], []]}