R/Shiny – 带有复选框和总计数的可滚动数据表格

huangapple go评论73阅读模式
英文:

R/Shiny - Scrollable datatable with checkboxes and total count

问题

我有一个数据表格,其中我添加了一个复选框列,并可以点击单个复选框。此外,还有一个 actionButton 可以选择或取消选择所有复选框,以及点击的复选框的总数和一个搜索框。除了以下三个问题外,一切都正常:

  1. 如果我点击单个复选框,计数不会改变。(但是对整个集合而言,它可以正常工作。)
  2. 如果我点击了一些复选框,然后立即搜索一个词或按任何列排序,复选框会被清除。
  3. 复选框列没有排序。如果对复选框进行排序,将累积所有已点击的复选框以便一目了然已选择了哪些,将会更理想。

有什么建议吗?

英文:

I have a datatable to which I add a checkbox column, and can click on individual boxes. Also, have an actionButton that can select or deselect all the checkboxes, a total count of the clicked boxes, and a search box. Everything works except for three things:

  1. If I click on individual checkboxes, the count doesn't change. (It works correctly, though, for the whole set.)
  2. If I click on a few checkboxes and I immediately search for a term or sort by any column, the checkboxes are cleared.
  3. There is no sorting for the checkbox column. It would be ideal if sorting the checkboxes could accumulate all those that were clicked at the top, to be able to see in one go what has been selected.

Any idea?

Thanks

library(shiny)
library(DT)

data <- data.frame(
  Checkbox         = rep(FALSE, 20),
  Name             = c("John", "Jane", "Michael", "Sara", "David","John1", "Jane1", "Michael1", "Sara1", "David1",
                       "John2", "Jane2", "Michael2", "Sara2", "David2","John3", "Jane3", "Michael3", "Sara3", "David3"),
  Volume           = round(100 * runif(20,0,1),0),
  stringsAsFactors = FALSE
)

ui <- fluidPage(
  titlePanel("Scrollable Datatable with Checkbox"),
  sidebarLayout(
    sidebarPanel(
      actionButton("selectBtn", "Select/Deselect All"),
      numericInput("selectedCount", "Selected Rows", 0, min = 0, max = nrow(data), width = "100%")
    ),
    mainPanel(
      DTOutput("myTable")
    )
  )
)

server <- function(input, output, session) {
  # Render the datatable
  output$myTable <- renderDT({
    datatable(data, 
              selection    = 'none',
              options      = list(
                scrollX    = TRUE,
                scrollY    = "400px",
                paging     = FALSE,
                searching  = TRUE,
                order      = list(1, 'asc'),
                columnDefs = list(
                  list(className = 'dt-center', targets = c(1, 3)),
                  list(className = 'dt-left', targets = 2),
                  list(targets = 1, render = JS(
                    "function(data, type, full, meta) {",
                    "var checkboxId = 'checkbox_' + meta.row;",
                    "return '<input type=\"checkbox\" id=\"' + checkboxId + '\" class=\"row-checkbox\" ' + (data ? 'checked' : '') + '></input>';",
                    "}"
                  ))
                )
              )
    )
  })
  
  # Select/Deselect all checkboxes     <============== (this works)
  observeEvent(input$selectBtn, {
    if (input$selectBtn %% 2 == 1) {
      data$Checkbox <- TRUE
    } else {
      data$Checkbox <- FALSE
    }
  # Update the datatable
    replaceData(proxy = dataTableProxy("myTable"), data, resetPaging = FALSE)
  # Update the selected count
    updateNumericInput(session, "selectedCount", value = sum(data$Checkbox))
  })
  
  # Row checkbox selection             <============== (this part doesn't work)
  observeEvent(input$myTable_cells_selected, {
    clicked_rows <- unique(input$myTable_cells_clicked$row)
    data$Checkbox[clicked_rows] <- !data$Checkbox[clicked_rows]
  # Update the datatable
    replaceData(proxy = dataTableProxy("myTable"), data, resetPaging = FALSE)
  # Update the selected count
    updateNumericInput(session, "selectedCount", value = sum(data$Checkbox))
  })
}

shinyApp(ui, server)

答案1

得分: 1

以下是翻译好的部分:

  • Use server=FALSE, otherwise you won't be able to get the total count and this is easier.

    • 使用 server=FALSE,否则您将无法获取总计数,这更容易。
  • Here is an app which adresses your issues except the total count (I'll do it later):

    • 这是一个应用程序,除了总计数之外,它解决了您的问题(我稍后会处理总计数):
  • library(shiny)

    • 加载库(shiny)
  • library(DT)

    • 加载库(DT)
  • ui <- fluidPage(

    • 用户界面 <- 流式页面(
  • checkboxColumn <- function(len, col, ...) { # col is the column index

    • checkboxColumn <- function(len, col, ...) { # col 是列索引
  • inputs <- character(len)

    • inputs <- character(len)
  • dat0 <- data.frame(

    • dat0 <- 数据框(
  • dat1 <- cbind(dat0, bool1 = FALSE, bool2 = FALSE)

    • dat1 <- cbind(dat0, bool1 = FALSE, bool2 = FALSE)
  • dat2 <- cbind(

    • dat2 <- cbind(
  • js <- function(dtid, cols, ns = identity) {

    • js <- function(dtid, cols, ns = identity) {
  • checkboxColumns <- c(3, 4)

    • checkboxColumns <- c(3, 4)
  • render <- function(col) {

    • render <- function(col) {
  • server <- function(input, output, session) {

    • server <- function(input, output, session) {
  • Dat <- reactiveVal(dat1)

    • Dat <- reactiveVal(dat1)
  • output[["dtable"]] <- renderDT({

    • output[["dtable"]] <- renderDT({
  • datatable(

    • datatable(
  • options = list(

    • options = list(
  • observeEvent(input[["dtable_cell_edit"]], {

    • observeEvent(input[["dtable_cell_edit"]], {
  • output[["reactiveDF"]] <- renderPrint({

    • output[["reactiveDF"]] <- renderPrint({
  • shinyApp(ui, server)

    • shinyApp(ui, server)
英文:

Use server=FALSE, otherwise you won't be able to get the total count and this is easier.

Here is an app which adresses your issues except the total count (I'll do it later):

library(shiny)
library(DT)

ui &lt;- fluidPage(
  br(),
  fluidRow(
    column(
      6,
      DTOutput(&quot;dtable&quot;)
    ),
    column(
      6,
      verbatimTextOutput(&quot;reactiveDF&quot;)
    )
  )
)

checkboxColumn &lt;- function(len, col, ...) { # `col` is the column index
  inputs &lt;- character(len)
  for(i in seq_len(len)) {
    inputs[i] &lt;- as.character(
      checkboxInput(paste0(&quot;checkb_&quot;, col, &quot;_&quot;, i), label = NULL, ...)
    )
  }
  inputs
}

dat0 &lt;- data.frame(
  fruit  = c(&quot;apple&quot;, &quot;cherry&quot;, &quot;pineapple&quot;, &quot;pear&quot;),
  letter = c(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;)
)

dat1 &lt;- cbind(dat0, bool1 = FALSE, bool2 = FALSE)

dat2 &lt;- cbind(
  dat0,
  check1 = checkboxColumn(nrow(dat0), 3),
  check2 = checkboxColumn(nrow(dat0), 4)
)

js &lt;- function(dtid, cols, ns = identity) {
  code &lt;- vector(&quot;list&quot;, length(cols))
  for(i in seq_along(cols)) {
    col &lt;- cols[i]
    code[[i]] &lt;- c(
      sprintf(
        &quot;$(&#39;body&#39;).on(&#39;click&#39;, &#39;[id^=checkb_%d_]&#39;, function() {&quot;,
        col),
      &quot;  var id = this.getAttribute(&#39;id&#39;);&quot;,
      sprintf(
        &quot;  var i = parseInt(/checkb_%d_(\\d+)/.exec(id)[1]);&quot;,
        col),
      &quot;  var value = $(this).prop(&#39;checked&#39;);&quot;,
      sprintf(
        &quot;  var info = [{row: i, col: %d, value: value}];&quot;,
        col),
      sprintf(
        &quot;  Shiny.setInputValue(&#39;%s&#39;, info);&quot;,
        ns(sprintf(&quot;%s_cell_edit:DT.cellInfo&quot;, dtid))
      ),
      &quot;});&quot;
    )
  }
  do.call(c, code)
}

checkboxesColumns &lt;- c(3, 4)

render &lt;- function(col) { 
sprintf(&#39;
function(data, type, row, meta) {
  if(type == &quot;sort&quot;) { 
    var i = meta.row + 1;
    var $box = $(&quot;#checkb_%d_&quot; + i);
    data = $box.prop(&quot;checked&quot;) ? &quot;true&quot; : &quot;false&quot;;
  }
  return data;
}&#39;, col)
}

server &lt;- function(input, output, session) {
  
  Dat &lt;- reactiveVal(dat1)
  
  output[[&quot;dtable&quot;]] &lt;- renderDT({
    datatable(
      dat2, 
      rownames = TRUE,
      escape = FALSE,
      editable = list(
        target = &quot;cell&quot;, disable = list(columns = checkboxesColumns)
      ),
      selection = &quot;none&quot;,
      callback = JS(js(&quot;dtable&quot;, checkboxesColumns)), 
      options = list(
        columnDefs = list(
         list(targets = 3, render = JS(render(3))),
         list(targets = 4, render = JS(render(4)))
        )
      )
    )
  }, server = FALSE)
  
  observeEvent(input[[&quot;dtable_cell_edit&quot;]], { 
    info &lt;- input[[&quot;dtable_cell_edit&quot;]] # this input contains the info of the edit
    Dat(editData(Dat(), info))
  })
  
  output[[&quot;reactiveDF&quot;]] &lt;- renderPrint({ 
    Dat()
  })
  
}

shinyApp(ui, server)

huangapple
  • 本文由 发表于 2023年6月8日 10:15:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76428171.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定