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:
- My file path in the code is for a windows os, change as required.
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()
)
)
Simple solution
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)
Intricate Solution
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.