Survey Shiny App : 随着页面的连续进行的进度条(多页,进度条和Shiny)

Survey Shiny App : A progress bar which progresses with the succession of pages (multiples pages, progress bar and Shiny)

早上好,晚上好, 希望你一切都好

我尝试用 Shiny 编写一个包含多个页面的调查应用程序。我使用 Shiny shinyWidgets 来安排我的问题,并使用 shinyjs 逐个问题地组织显示。代码如下。一切正常。

我会编写一个进度条:这样受访者就可以知道他在问卷中的位置。这是个好主意,不是吗?好吧,但是当我尝试对我的想法进行编程时,困难开始了。

我不知道如何使用我的按钮来操作我的进度条。我有从 0 到 ... 的按钮(在我的示例 2 中)。我不知道如何根据按钮告诉我的进度条如何前进。

编辑: 例如,如果有 10 页(因此有 10 个“下一个”按钮),当单击第一个下一个按钮(按钮 1 --> 移动在第二页上),我的进度条移动到 10%。当点击第二个按钮时(按钮 2 --> 在第三页上移动),我的进度条移动到 20%,....因此,当单击最后一个按钮(按钮 10 --> 最后一个问题)时,我的进度条移动到 100%。

在我下面的例子中,我有 2 个问题。所以,当我点击按钮 1 时,进度条会在 50%。当我点击按钮 2 时,进度条会在 100%

提前谢谢你, Aurélien.

library(shiny)
library(shinyWidgets)
library(shinyjs)

shinyApp(
  ui = fluidPage(
    style = "width:800px",
    titlePanel(
      fluidRow(column(width=2, img(src="myImage.png")), 
               column(width=10, progressBar(id = "progress", value = 0, total = 100, display_pct = TRUE)))),
               
    shinyjs::useShinyjs(), 
    
    panel(
      
    div(id = "Intro", 
    h4("Bienvenue sur notre questionnaire en ligne. Nous vous remercions d’accepter de répondre à cette étude en ligne menée 
      par l’Institut d’études et de sondages Su-R-vey. Cette étude sera traitée de façon anonyme. Nous vous garantissons la 
      confidentialité de cette interview. Ce questionnaire vous prendra une vingtaine de minutes."), 
    
    actionButton("button0", "Suivant")),
    
    # Question S1. 
    hidden(div(id = "S1",
               
    radioGroupButtons("S1", label = p("Vous êtes :"),
                                 choices = list("Un Homme" = 1, "Une femme" = 2), selected = "", direction = "vertical"),
               
    actionButton("button1", "Suivant"))), 
    
    # Question S2. 
    hidden(div(id = "S2",
               
               numericInput("S2", label = p("Quel âge avez-vous ?"), value = ""),    
               
               actionButton("button2", "Suivant"))), 
    
    # Fin du questionnaire
    hidden(div(id = "fin", 
               
               p("Ce questionnaire est à présent terminé. Je vous remercie vivement pour votre participation et je vous souhaite une bonne fin de journée / soirée"),
               
               actionButton("submit", "Submit"))) 
    
    )),
  
  server = function(input, output, session) {
    
    observeEvent(input$button0, {
      shinyjs::hide(id = "Intro")
      shinyjs::show(id = "S1")
    })
    
      observeEvent(input$button1, {
      shinyjs::hide(id = "S1")
      shinyjs::show(id = "S2")
    })
      
      observeEvent(input$button2, {
        shinyjs::hide(id = "S2")
        shinyjs::show(id = "fin")
      })
      
      observeEvent(input$button0, {
        for (i in 1:100) {
          updateProgressBar(
            session = session,
            id = "progress",
            value = i, total = 100,
            title = paste("Process", trunc(i/10))
          )
        }
      })
    
})

去掉所有与进度条维护无关的东西,这里是一个MWE:

library(shiny)
library(shinyWidgets)

ui = fluidPage(
    style = "width:800px",
    panel(progressBar(id = "progress", value=0, total=100, display_pct = TRUE)),
    panel(uiOutput("pageContent")),
    actionButton("button", "Suivant")
  )
  
server = function(input, output, session) {
  v <- reactiveValues(
    currentPage=1,
    nPages=10 # nPages doesn't need to be reactive for this MWE, but might need to be in reality
  )
  observe({
    updateProgressBar(session, "progress", value=v$currentPage, total=v$nPages)
  })
  output$pageContent <- renderUI({
    paste0("Content for page ", v$currentPage)
  })
  observeEvent(input$button, {
    v$currentPage <- v$currentPage + 1
    if (v$currentPage == (v$nPages+1)) {
      # Finish processing here
    } else { 
      updateProgressBar(session, "progress", value=v$currentPage*v$nPages, total=100) # Total required to force indicator updatde
      updateActionButton(session, "button", label=ifelse(v$currentPage == v$nPages, "Fin", "Suivant"))
    }
  })
}

shinyApp(ui = ui, server = server)

您的主要工作是更新 output$pageContent。我会考虑让每个页面成为一个单独的模块。尽管这不是绝对必要的(因为每个页面只会有一个实例),但我认为它仍然是值得的,因为它可以保护您免受 inputoutput id 的意外重复并保持清晰的分离在“问卷展示”和“问卷进度管理”之间。