Hi all. I am new to reflex and I am trying to use the form components to create a survey tool. The idea is to avoid hard coding the questions/response options so the tool can run a variety of surveys.
My actual question: Is there a way to reuse the same radio group responses without the prior choice appearing as a default selection for the next choice?
Some more background: I set the questions using (in this case) a data frame with each row containing the needed information for a question. The row includes instructions, the actual prompt, any response options, a variable indicating what form tool should be used and IDs to control other information about the question. The survey page iterates through each row, modifying the survey state as needed, with the updates being triggered by the survey form submit action. This way, the user sees one question at a time, which is important for some of the questions I intend to implement.
The trouble is that if the same set of radio group options appears in two questions in sequence, then the selection from the prior option will appear in the second radio group. The code below will reproduce the trouble I am having. If you run it, you will see that if you make a choice for the third question, it will appear in the fourth question’s radio group.
Things I have tried: I see in the documents it is possible to create a component state, which I thought would solve my problem, but it did not. I could successfully get two components isolated from one another but when the survey state updated, each component state “remembered” the user’s last choice. I also notice that if the questions do not have the same options back-to-back, then the problem does not happen, so a hack I discovered would be to load a blank component between each question, but this is unappealing.
Maybe my general approach here is not a good one. I am open to alternatives.
example code
import pandas as pd
import numpy as np
import reflex as rx
# an example data frame
df = pd.DataFrame({'IB': ['Welcome. Click Next to continue.',
'Please answer the following questions.',
'Please read the following statements and chose the option that fits you best.',
'Please read the following statements and chose the option that fits you best.',
'Please read the following statements and chose the option that fits you best.'],
'SB': ['',
'Do you currently live in the US?',
'Politicians should always listen closely to the problems of the people.',
'Politicians don’t have to spend time among ordinary people to do a good job.',
'The will of the people should be the highest principle in this country’s politics.'],
'AB': ['Next', 'Next', 'Next', 'Next', 'Submit'],
'Inst': [np.nan, 'radio', 'radio', 'radio', 'radio' ],
'RB1': [np.nan, 'Yes', 'Agree', 'Agree', 'Agree'],
'RB2': [np.nan, 'No', 'Slightly Agree', 'Slightly Agree', 'Slightly Agree' ],
'RB3': [np.nan, np.nan, 'Neutral', 'Neutral', 'Neutral'],
'RB4': [np.nan, np.nan, 'Slightly Disagree', 'Slightly Disagree', 'Slightly Disagree'],
'RB5': [np.nan, np.nan, 'Disagree', 'Disagree', 'Disagree'],
'SID': ['welcome', 'liveUS', 'pscore1', 'pscore2', 'pscore3']})```
# set up survey state
class SurveyState(rx.State):
"""The app state."""
response_data: dict = {} # where the responses will be saved
page_num: int # where we are in the survey
survey_pages: pd.DataFrame # all the items in the survey
current_page: pd.DataFrame # the current survey item
IB: str # text for response instuctions (eg: select all that apply)
SB: str # text for stimulus (eg: "What year were you born?")
AB: str # text for submit buttion (eg: "Next")
Inst: str # ID for form type (eg: 'radio', dropdown, range slider,)
response_option: list # response options (eg: ['strongly agree', 'agree', ..., 'strongly disagree'])
SID: str # stimulus ID (unique question id, eg: "Pop_scale_1")
def setup(self):
self.survey_pages = df
self.control()
def control(self):
# extract current page data
self.current_page = self.survey_pages.iloc[self.page_num, :]
# set basic params
self.IB = self.current_page['IB']
self.SB = self.current_page['SB']
self.AB = self.current_page['AB']
self.Inst = self.current_page['Inst']
self.SID = self.current_page['SID']
# extract response options
self.response_option = self.current_page.filter(like='RB').dropna().to_list()
def close_out(self):
"""Handle survey completion."""
pass
def question_submit(self, response_data: dict):
self.response_data = {**self.response_data, **response_data}
self.page_num += 1
if self.page_num <= self.survey_pages.shape[0]:
self.control() # next question
else:
self.close_out() # close out the survey
@rx.page(on_load=SurveyState.setup) # start the survey
def index() -> rx.Component:
return(
rx.container(
rx.form(
rx.flex(
rx.center(rx.box(SurveyState.IB, margin_bottom='10px')),
rx.center(rx.box(SurveyState.SB), margin_bottom='20px'),
rx.match(
SurveyState.Inst,
('radio', rx.center(rx.box(rx.radio(SurveyState.response_option,
name=SurveyState.SID)))),
('drop', rx.center(rx.box('TEST drop down'))),
rx.center(rx.box(''))
),
rx.box(
rx.button(SurveyState.AB, type='submit'),
text_align='center',
padding='20px'
),
direction='column'
),
on_submit=SurveyState.question_submit,
reset_on_submit=True
)
)
)
app = rx.App()
app.add_page(index)