When using the interactive shiny app you can use one of the different
available questionnaires to e.g. conduct a web survey
(questionnaire_web_survey()
) or collect data from
interviewer-administered (phone) interviews
(questionnaire_interviewer_administered()
).
To be as flexible as possible, you can also modify these existing questionnaires or just build your own one from scratch.
Pages 📃
All questionnaires are built on top of pages. New pages can be
created using the function new_page()
, the documentation of
which is essential reading for those who want to design their own
pages.
There exist some helper functions that make it simple to create specific types of question pages:
In general each page has a unique page_id
to identify
itself and follows a general principle of lifecycle functions. Most of
these lifecycle functions are optional, except for the
render
function, which should return the shiny HTML
tags or inputs / outputs to be displayed. All lifecycle functions
take at least the shiny session as arguments, other arguments depend on
the function itself (supported arguments are listed in
new_page()
).
Tip: When implementing your own pages, we recommend to use
...
as the last parameter in all of them to allow for potentially new parameters to be added.
To find some useful pre-built pages or helper functions to easily
generate commonly used pages check out all functions whose name starts
with page_
in the reference.
Page Lifecycle
The lifecycle of a page is as follows: First, its
condition
will be run to check whether the page should be
displayed at all. If this function returns FALSE
the page
will be skipped and the condition for the following one will be
evaluated.
If the condition is TRUE
, the page will be shown. To do
this the function run_before
will be run to prepare
everything for the page, followed by render
to generate the
page’s actual outputs (ata returned from run_before
is
available in render
under the name
run_before_output
).
When the user navigates away from a page and to the next page, the
function run_after
will be called which can be used to
capture user input and save data. Then, the next page’s
condition
will be checked and so on.
If the user wants to go back to the previous page,
run_after
will not be called and the previous page will be
shown. The condition
of the page that the user visited
before will not be checked again.
A more detailed description of the page lifecycle can be found in the
documentation for new_page()
.
Saving Data
All existing pages (e.g. page_first_freetext()
,
page_select_suggestion()
) and page helpers
(e.g.page_choose_one_option()
,
page_freetext()
) will automatically save user input (as
long as it is not explicitly disabled in the
app_settings
).
When building your own pages from scratch, however, you will have to
make sure to specify which data should be saved in the app. This can be
done by using set_item_data()
. If data is saved using this
function, it will automatically be saved with the other data, yet we
always recommend verifying that questionnaire data is saved as expected
before starting proper data collection.
For a detailed description of what data is saved by default and in
which format, examine the section “data” in
vignette("app")
.
Questionnaires 📑
Building your Own ✨
Once you’re comfortable building your own pages, building your own questionnaire is trivial, as a questionnaire is merely a list of pages.
An example for a simple questionnaire would be:
library(occupationMeasurement)
library(shiny)
my_simple_questionnaire <- list(
new_page(
page_id = "test",
render = function(...) {
return(list(
p("Hello!"),
button_previous(),
button_next()
))
}
),
# Create a custom page to choose your favorite meal
page_choose_one_option(
page_id = "favourite_meal",
question_text = "Please pick your favorite kind of meal.",
list_of_choices = list(
"Breakfast" = 1,
"Lunch" = 2,
"Dinner" = 3
)
)
)
# Test the questionnaire in the app
# app(questionnaire = my_simple_questionnaire)
As the general goal of this package is the measurement of occupations, you will usually want to at least include the core set of pages:
list(
# ... some of your pages before ...
page_first_freetext(),
page_second_freetext(),
page_select_suggestion(),
page_none_selected_freetext(),
page_followup(1),
page_followup(2)
# ... some of your pages after ...
)
Modifying an Existing One
Apart from creating a new questionnaire from scratch, it’s also possible to take an existing questionnaire and modify it to suit your needs.
To do this you can modify the questionnaire itself, by adding, removing or overwriting pages into it (as the questionnaire is just a list, it can be modified just like one).
library(occupationMeasurement)
library(shiny)
questionnaire <- questionnaire_web_survey()
# Remove the first page (welcome)
questionnaire[[1]] <- NULL
# Use c() to add a new alternative page at the start
questionnaire <- c(
list(
new_page(
"my_welcome",
render = function() {
return(h1("Hello!"))
}
)
),
questionnaire
)
# Test the questionnaire in the app
# app(questionnaire = questionnaire)
Alternatively it’s also possible to modify pages themselves (albeit a
bit more complicated). Under the hood, pages are essentially also
powered by lists and therefore their parameters can just be overwritten
e.g. removing a page’s condition check can be done by overwriting it via
page$condition <- NULL
.
As a page’s different parameters usually depend on each other it’s much easier to accidentaly break something. Therefore it is in general a good practice to overwrite a page’s function by just wrapping it, like the example below.
library(occupationMeasurement)
library(shiny)
questionnaire <- questionnaire_web_survey()
# Add some text to page_select_suggestion
print(questionnaire[[4]]$page_id)
#> [1] "none_selected_freetext"
original_select_suggestion_render <- questionnaire[[4]]$render
questionnaire[[4]]$render <- function(...) {
return(c(
list(
p("~ My custom text before ~")
),
original_select_suggestion_render(...)
))
}
# Test the questionnaire in the app
# app(questionnaire = questionnaire)