I am trying to learn how to create a questionnaire with Shiny. I need that each question is on a new page. For example, when the user answers to a question, press "Next" button and a new page loads with another question. Any idea on how this is done? Because I want to simplify my code, I created a module for each question. The ui
would look like this:
library(shiny)
fluidPage(
div(class = 'container',
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
h1("Welcome!"),
p("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "),
br(),
actionButton("page1", "Start")
)),
source("questions/question1.R", local = TRUE)$value,
source("questions/question2.R", local = TRUE)$value
)
Module Question 1:
div(class = 'container',
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
radioButtons("question1", "Please select a number: ", choices = c(10,20,30)),
actionButton("page3", "Next"),
br()
)
)
Module Question 2:
div(class = 'container',
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
radioButtons("question2", "Please select a color: ", choices = c("Blue", "Orange", "Red")),
actionButton("page3", "Next"),
br()
)
)
... and the server.R:
server <- function(input, output, session) {
}
So, when the user press "Start" should go to page 1 and so on... Thanks!
I think there are a few ways to do this in shiny
. I'll start with the simplest which does not solve the problem exactly and add an alternative.
I setup the question .R
files as per below:
Module Question 1:
div(class = 'container',
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
radioButtons("question1", "Please select a number: ", choices = c(10,20,30)),
actionButton("block_two", "Next"),
br()
)
)
Module Question 2:
div(class = 'container',
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
radioButtons("question2", "Please select a color: ", choices = c("Blue", "Orange", "Red")),
actionButton("block_three", "Next"),
br()
)
)
You could use the observeEvent
and renderUI
in shiny
. This will allow you to pull in the neat code blocks from separate .R
files and render them sequentially as the user clicks next.
Note: This however does not render the UI elements on a new page.
library(shiny)
ui <- fluidPage(
uiOutput("home"),
uiOutput("block_one"),
uiOutput("block_two")
)
server <- function(input, output, session) {
output$home <- renderUI({
div(class = 'container', id = "home",
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
h1("Welcome!"),
p("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "),
br(),
actionButton("block_one", "Start")
))
})
observeEvent(input$block_one, {
output$block_one <- renderUI({ source("questions\\question1.R", local = TRUE)$value })
})
observeEvent(input$block_two, {
output$block_two <- renderUI({ source("questions\\question2.R", local = TRUE)$value })
})
}
shinyApp(ui, server)
This requires you to create a render_page
function which one can then use to render these new UI components on a new page. You then just need to create a function for each component and call renderUI
.
I am not a massive fan of this as you will then need to create navigation buttons, and then might as well use shinydashboard
.
However, if you are planning on creating a really long questionnaire then one could do the below:
I've left the function(...)
as is in case you would like to pass additional arguments when rendering the UI components.
library(shiny)
ui <- (htmlOutput("page"))
home <- function(...) {
args <- list(...)
div(class = 'container', id = "home",
div(class = 'col-sm-2'),
div(class = 'col-sm-8',
h1("Welcome!"),
p("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "),
br(),
actionButton("block_one", "Start")
))
}
question_one <- function(...) {
renderUI({ source("questions\\question1.R", local = TRUE)$value })
}
question_two <- function(...) {
renderUI({ source("questions\\question2.R", local = TRUE)$value })
}
render_page <- function(...,f, title = "test_app") {
page <- f(...)
renderUI({
fluidPage(page, title = title)
})
}
server <- function(input, output, session) {
## render default page
output$page <- render_page(f = home)
observeEvent(input$block_one, {
output$page <- render_page(f = question_one)
})
observeEvent(input$block_two, {
output$page <- render_page(f = question_two)
})
}
shinyApp(ui, server)
There is a decent r-blogger post on creating this architecture: https://www.r-bloggers.com/some-thoughts-on-shiny-open-source-render-multiple-pages/
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With