在 Shiny 中,如何在没有 javascript 的情况下一次显示一个选项卡,等等

In Shiny, how to make tabs appear one at a time without javascript, etc

我想使用一组 ifelse 语句来 select 哪个 tabsetPanel 使用。这个想法是在用户执行先决条件任务时出现新的选项卡。我创建的内容似乎试图做到这一点,但现有选项卡会重新加载,重置选项卡的状态,因此删除刚刚添加的选项卡。在我的示例中,您可以看到第二个选项卡闪现,然后消失。如何使每个选项卡中的输入在重新创建 tabsetPanel 时保持不变?我阅读了对 a similar question 的回复,但我不熟悉 javascript(或该答案中 tags$script 中的任何代码),所以我想要一个只需要 R 代码的解决方案.

该应用是 available on shinyapps

代码贴在下面,也是available on github.

ui.R

library(shiny)
shinyUI(pageWithSidebar(
  headerPanel("Subset data before analyzing"),
  sidebarPanel(),
  mainPanel(uiOutput("Panels"))
))

server.R

library(shiny)
shinyServer(function(input, output) {  

  #This is the data
  d1 = data.frame(
    Student = c("Abe","Bill","Clare","Abe","Bill","Clare"),
    Class = c("ELA","ELA","ELA","Math","Math","Math"),
    Grade = c(71,72,73,74,75,76))

  # This pulls a list of unique names from the Student column of the data and creates a checklist
  output$StudentCheckList <- renderUI({
    if(is.null(d1)){return ()
    } else tagList(
      checkboxGroupInput(inputId = "SelectedStudents", 
                         label = "Which students you like to select?", 
                         choices = unique(as.character(d1$Student)))
    )
  })

  #This pulls a list of unique names from the Class column of the data and creates a checklist
  output$ClassCheckList <- renderUI({
    if(is.null(d1)){return ()
    } else tagList(
      checkboxGroupInput(inputId = "SelectedClasses", 
                         label = "Which classes would you like to select?", 
                         choices = unique(as.character(d1$Class)))
    )
  })

  # This generates the table of data subsetted by the checklist selections
  output$Summary = renderTable({
    if(is.null(d1)){return ()
    } else {
      d3 = d1[which(as.character(d1$Student) %in% input$SelectedStudents),]
      d3 = d3[which(as.character(d3$Class) %in% input$SelectedClasses),]
      return(d3)
    }
  })

    # These are the definitions for the individual panels
  p1 = reactive(tabPanel("Pick Students",uiOutput("StudentCheckList")))
  p2 = reactive(tabPanel("Pick Classes",uiOutput("ClassCheckList")))
  p3 = reactive(tabPanel("Summary",tableOutput("Summary")))

  # This generates the actual panel layout
  output$Panels = renderUI({
    tagList(
      if(is.null(d1)){return()
      } else if (length(input$SelectedStudents)==0){tabsetPanel(p1())
      } else if (length(input$SelectedClasses)==0){tabsetPanel(p1(),p2())
      } else tabsetPanel(p1(),p2(),p3())
      )
  })
})

我找到了解决这个问题的办法。它涉及几个组件。

首先,我必须创建一个新版本的 tabsetPanel 函数(我称之为 tabsetPanel2。它与 tabsetPanel 本质上相同,只是它删除了任何 tabPanel 为 NULL 的对象。这样,任何不应出现的 tabPanel 对象都可以设置为 NULL,并且对 tabsetPanel 的调用不必更改。

其次,我必须创建反应对象来保存用户在驻留在 tabPanel 上的每个小部件上所做的选择,并将小部件的 selected 参数设置为该反应目的。这样,当 tabsetPanel2 重建时,它会加载之前输入的信息。

第三,我必须创建一个反应对象来保存所选选项卡的名称。这样,当 tabsetPanel2 重建时,它会自动转到用户刚刚所在的选项卡。

所有代码都可以在问题中提到的 github 存储库中找到。