r - 'Select All' checkbox for Shiny DT::renderDataTable


Keywords:r 


Question: 

I want a checkbox that selects all the rows displayed (displayed is key as this differs between the filters you have applied and the entire data table) in a standard DT::renderDataTable in Shiny.

Is there any DT extension that already does this? My coding skills are basic so I cannot write an equivalent Java or HTML code.

This is my app so far, any csv file is compatible for the select all purpose. At the moment there is a clunky way of creating another table of all the selected rows (manually selected one by one) - this is difficult when you want to select 30 animals all with the same characteristic.

library(shiny)
library(shinyjs)
library(DT)
library(dplyr)
library(data.table)



ui = pageWithSidebar(

  headerPanel(""),

  #This is where the full animal information file is input, as a ".txt" file.
  sidebarPanel(
    fileInput("ani", "Upload Animal Information File", accept = ".csv"),
    br(),
    numericInput("groups","Number of Ewe Groups", value = 1 ),
    #This is a list of the table headers. These headers can be indivdually selected to be part of the concatenated "Unique ID" single column.  
    uiOutput("choose_columns"),
    width = 2),
  mainPanel(
  DT::dataTableOutput("ani1"),
  DT::dataTableOutput("selectedEwes")
))






server = function(input, output, session) {

    animalinformation <- reactive({
        file1 <- input$ani
        if (is.null(file1))
            return(NULL)
        #This removes the Ewes and Status non-zero Rams from the displayed data, so that only live/at hand Rams are shown for selection.    
        isolate({
            anifile <- read.csv(file1$datapath, header = TRUE)
            anifile <- as.data.frame(anifile)
        })
        anifile
    })


    output$choose_columns <- renderUI({
        if (is.null(animalinformation()))
            return()
        colnames <- names(animalinformation())


        # Create the checkboxes and select them all by default
        checkboxGroupInput("columns", "Choose Columns",
                       choices = colnames,
                       selected = colnames)
    })




    #This line is repsonsible for creating the table for display.
    output$ani1 = DT::renderDataTable({
        if (is.null(animalinformation()))
            return()
        if (is.null(input$columns) || !(input$columns %in% names(animalinformation()))) { return() }
            { datatable(animalinformation()[, input$columns, drop = F], filter = "top") }
    })


    ani1_selected <- reactive({
        ids <- input$ani1_rows_selected
        animalinformation()[ids,]
    })





    #This displays the table of selected rows from the table of Rams. This table can be downloaded or printed, or copied using the buttons that appear above the table, thanks to the 'Buttons' extension.
    output$selectedEwes <- DT::renderDataTable({
        datatable(
      ani1_selected(),
      selection = list(mode = "none"),
      caption = "Copy to clipboard, download a .csv or print the following table of selected Ewes, using the above buttons.", extensions = 'Buttons', options = list(dom = 'Bfrtip', buttons = c('copy', 'csv', 'excel', 'pdf', 'print'))
    )
    })





}

shinyApp(ui = ui, server = server)

Any help would be much appreciated thanks.


1 Answer: 

Here is the simplest implementation I can think of. It takes advantage of the fact that DT will return the filter row indexes back to R, which is input$dt_rows_all in the below example. Moreover, it uses the DT::dataTableProxy() to control the row selection. Finally, it works in both the client mode and the server-side processing mode.

By the way, I want to mention that using javascript to mimic the selecting / deselecting events in DT won't change the related shiny binding values in R (e.g., input$dt_rows_selected). It's because DT has its own implementation of row selections (may change in the future but not yet at the time of writing). See rstudio/DT#366 if you want to know more.

library(shiny)
ui <- tagList(
  DT::DTOutput("dt"),
  checkboxInput("dt_sel", "sel/desel all"),
  h4("selected_rows:"),
  verbatimTextOutput("selected_rows", TRUE)
)

server <- function(input, output, session) {
  dat <- reactive({iris})
  output$dt <- DT::renderDT(dat(), server = TRUE)
  dt_proxy <- DT::dataTableProxy("dt")
  observeEvent(input$dt_sel, {
    if (isTRUE(input$dt_sel)) {
      DT::selectRows(dt_proxy, input$dt_rows_all)
    } else {
      DT::selectRows(dt_proxy, NULL)
    }
  })
  output$selected_rows <- renderPrint(print(input$dt_rows_selected))
}

shiny::runApp(list(ui = ui, server = server))