在多页数据表中注册所有输入

标签 r shiny dt

我有一个数据表,我在其中添加了复选框供我的用户选择各种选项。不幸的是,shiny 似乎看到的唯一输入是已经显示在表中的输入。因此,如果我有多个页面,我只能看到前 10 个输入。

在下面的示例中,我打印了我可以看到的所有在数据表对象上方注册的输入。目前,我只看到前 10 个输入 (A - J)。我希望能够在表格首次加载时看到所有 26 个(无需切换页面)。

在我的实际应用程序中,我有多列复选框,因此行选择是不够的。关于如何一次注册所有 26 个输入的任何提示或建议?

library(shiny)
library(DT)

shinyInput <- function (FUN, id_base, suffix, label = "", ...) 
{
  inputId <- paste0(id_base, suffix)
  args <- list(...)
  args <- c(list(label = label), args)
  args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
  rv <- character(length(inputId))
  for (i in seq_along(rv)) {
    this_arg <- lapply(args, `[`, i)
    ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
    rv[i] <- as.character(ctrl)
  }
  rv
}

X <- data.frame(id = LETTERS, 
                selected = sample(c(TRUE, FALSE), 
                                  size = length(LETTERS), 
                                  replace = TRUE))

X$IsSelected <- 
  shinyInput(
    shiny::checkboxInput, 
    id_base = "new_input_", 
    suffix = X$id, 
    value = X$selected
  )

shinyApp(
  ui = fluidPage(
    verbatimTextOutput("value_check"),
    textOutput("input_a_value"),
    DT::dataTableOutput("dt")
  ), 
  
  server = shinyServer(function(input, output, session){
    
    Data <- reactiveValues(
      X = X
    )
    
    output$value_check <- 
      renderPrint({
        sort(names(input))
      })
    
    output$dt <- 
      DT::renderDataTable({
        
        
        DT::datatable(X, 
                      selection = "none", 
                      escape = FALSE, 
                      filter = "top", 
                      #rownames = FALSE, 
                      class = "compact cell-border", 
                      options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                                     drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
      })
  })
)

附录

下一个例子有点复杂,但更能说明问题的动机。看来最大的问题是我想使用诸如“全选”之类的按钮。此外,当与框交互时,我不会立即处理任何操作。取而代之的是,用户进行选择,并且在单击“保存选择”按钮之前不会保存选择。

发生的事情是我点击“全选”按钮,它会检查所有已经绘制的输入框。如果我只查看了表格的第一页,它只会更新那些输入,而不会更新接下来几页的任何输入。这确实是我需要改变的行为。

# Set up environment ------------------------------------------------
library(shiny)
library(DT)
library(magrittr)

# Example of data coming from the database. -------------------------

set.seed(pi^2)

SourceData <- 
  data.frame(sample_id = 1:25, 
             is_selected = sample(c(TRUE, FALSE), 25, replace = TRUE))


# Support Functions -------------------------------------------------
# These would exist, for example, in an internal package

shinyInput <- function (FUN, id_base, suffix, label = "", ...) 
{
  inputId <- paste0(id_base, suffix)
  args <- list(...)
  args <- c(list(label = label), args)
  args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
  rv <- character(length(inputId))
  for (i in seq_along(rv)) {
    this_arg <- lapply(args, `[`, i)
    ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
    rv[i] <- as.character(ctrl)
  }
  rv
}

prepareDataForDisplay <- function(Data){
  Data$is_selected <- 
    shinyInput(shiny::checkboxInput, 
               id_base = "is_selected_", 
               suffix = Data$sample_id, 
               value = Data$is_selected)
  
  Data
}

# User Interface ----------------------------------------------------

ui <- 
  fluidPage(
    verbatimTextOutput("value_check"), 
    
    actionButton(inputId = "btn_saveSelection", 
                 label = "Save Selection"), 
    actionButton(inputId = "btn_selectAll", 
                 label = "Select All"),
    actionButton(inputId = "btn_unselectAll", 
                 label = "Unselect All"),
    actionButton(inputId = "btn_restoreDefault", 
                 label = "Restore Default (select odd only)"),
    
    DT::dataTableOutput("dt")
  )

# Server ------------------------------------------------------------

server <- 
  shinyServer(function(input, output, session){
    
    # Event Observers -----------------------------------------------
    
    observeEvent(
      input$btn_selectAll, 
      {
        check_input <- names(input)[grepl("is_selected_", names(input))]
        
        lapply(check_input, 
               function(ci){
                 updateCheckboxInput(session = session, 
                                     inputId = ci, 
                                     value = TRUE)
               })
      }
    )
    
    observeEvent(
      input$btn_unselectAll, 
      {
        check_input <- names(input)[grepl("is_selected_", names(input))]
        
        lapply(check_input, 
               function(ci){
                 updateCheckboxInput(session = session, 
                                     inputId = ci, 
                                     value = FALSE)
               })
      }
    )
    
    observeEvent(
      input$btn_restoreDefault,
      {
        check_input <- names(input)[grepl("is_selected_", names(input))]

        lapply(check_input, 
               function(ci){
                 id <- as.numeric(sub("is_selected_", "", ci))
                 
                 updateCheckboxInput(session = session, 
                                     inputId = ci, 
                                     value = id %% 2 == 1)
               })
      }
    )
    
    observeEvent(
      input$btn_saveSelection,
      {
        check_input <- names(input)[grepl("is_selected_", names(input))]
        
        id <- as.numeric(sub("is_selected_", "", check_input))

        for (i in seq_along(check_input)){
          SourceData$is_selected[SourceData$sample_id == id[i]] <- 
            input[[check_input[i]]]
        }

        # At this point, I would also save changes to the remote database.
        
        DT::replaceData(proxy = dt_proxy, 
                        data = prepareDataForDisplay(SourceData))
      }
    )
    
    # Output elements -----------------------------------------------
    
    output$value_check <- 
      renderPrint({
        sort(names(input))
      })
    
    output$dt <- 
      DT::renderDataTable({
        SourceData %>% 
          prepareDataForDisplay() %>% 
          DT::datatable(selection = "none", 
                        escape = FALSE, 
                        filter = "top", 
                        class = "compact cell-border", 
                        options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                                       drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
      })
    
    dt_proxy <- DT::dataTableProxy("dt")
    
  })

# Run the application -----------------------------------------------

shinyApp(
  ui = ui, 
  server = server
)

最佳答案

这是基于您的附录的解决方法(不确定您是否需要关于 btn_restoreDefaultbtn_saveSelection 的更改),但一般过程应该很清楚:

# Set up environment ------------------------------------------------
library(shiny)
library(DT)
library(magrittr)

# Example of data coming from the database. -------------------------

set.seed(pi^2)

SourceData <- 
  data.frame(sample_id = 1:25, 
             is_selected = sample(c(TRUE, FALSE), 25, replace = TRUE))


# Support Functions -------------------------------------------------
# These would exist, for example, in an internal package

shinyInput <- function (FUN, id_base, suffix, label = "", ...) 
{
  inputId <- paste0(id_base, suffix)
  args <- list(...)
  args <- c(list(label = label), args)
  args <- lapply(args, function(a) rep(a, length.out = length(inputId)))
  rv <- character(length(inputId))
  for (i in seq_along(rv)) {
    this_arg <- lapply(args, `[`, i)
    ctrl <- do.call(FUN, c(list(inputId = inputId[i]), this_arg))
    rv[i] <- as.character(ctrl)
  }
  rv
}

prepareDataForDisplay <- function(Data){
  Data$is_selected <- 
    shinyInput(shiny::checkboxInput, 
               id_base = "is_selected_", 
               suffix = Data$sample_id, 
               value = Data$is_selected)
  
  Data
}

# User Interface ----------------------------------------------------

ui <- 
  fluidPage(
    verbatimTextOutput("value_check"), 
    
    actionButton(inputId = "btn_saveSelection", 
                 label = "Save Selection"), 
    actionButton(inputId = "btn_selectAll", 
                 label = "Select All"),
    actionButton(inputId = "btn_unselectAll", 
                 label = "Unselect All"),
    actionButton(inputId = "btn_restoreDefault", 
                 label = "Restore Default (select odd only)"),
    
    DT::dataTableOutput("dt")
  )

# Server ------------------------------------------------------------

server <- 
  shinyServer(function(input, output, session){
    
    # Event Observers -----------------------------------------------
    
    observeEvent(
      input$btn_selectAll, 
      {
        TmpData <- SourceData
        TmpData$is_selected <- TRUE
        replaceData(dt_proxy, prepareDataForDisplay(TmpData))
      }
    )
    
    observeEvent(
      input$btn_unselectAll, 
      {
        TmpData <- SourceData
        TmpData$is_selected <- FALSE
        replaceData(dt_proxy, prepareDataForDisplay(TmpData))
      }
    )
    
    observeEvent(
      input$btn_restoreDefault, 
      {
        replaceData(dt_proxy, prepareDataForDisplay(SourceData))
      }
    )
    
    observeEvent(
      input$btn_saveSelection,
      {
        
        check_input <- names(input)[grepl("is_selected_", names(input))]
        
        id <- as.numeric(sub("is_selected_", "", check_input))
        
        TmpData <- SourceData 
        
        for (i in seq_along(check_input)){
          TmpData$is_selected[TmpData$sample_id == id[i]] <- 
            input[[check_input[i]]]
        }
        
        # At this point, I would also save changes to the remote database.
        
        DT::replaceData(proxy = dt_proxy, 
                        data = prepareDataForDisplay(TmpData))
      }
    )
    
    # Output elements -----------------------------------------------
    
    output$value_check <- 
      renderPrint({
        sort(names(input))
      })
    
    output$dt <- 
      DT::renderDataTable({
        SourceData %>% 
          prepareDataForDisplay() %>% 
          DT::datatable(selection = "none", 
                        escape = FALSE, 
                        filter = "top", 
                        class = "compact cell-border", 
                        options = list(preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
                                       drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')))
      })
    
    dt_proxy <- DT::dataTableProxy("dt")
    
  })

# Run the application -----------------------------------------------

shinyApp(
  ui = ui, 
  server = server
)

关于在多页数据表中注册所有输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70393689/

相关文章:

r - 在已经存储在 Shiny 服务器上的文件中进行选择

r - 我们如何通过管道工 web api 返回 ggplot 图?

R shiny : how to not update all input elements of a matrix created in server. r(显然隔离不够)

r - Shiny 的非 react 范围

r - Shiny :如何在数据表中显示条形图

r - 用于显示表格的 Shiny 模块

r - 绘图显示在 renderTable 但不是 DT::renderDataTable

r - ggplot 与来自数据表 (DT) 的过滤数据和 react 性小部件来选择 x 和 y 轴

R Forestplot 不允许在 labeltext 中使用 is.summary 进行表达式?

r - 如何将数据列转换为 z 分数?