Search code examples
jqueryrshinydatatablesshinydashboard

Shiny: trigger datatable export button with custom button


I want to trigger the csv-export button of a data table with a custom actionButton in the sidebar of shinydashboard.

However, I do not get it working since the pressed actionButton does not start the download. Could someone please help me with this problem?

And is it possible to hide the csv-export button in the data table?

enter image description here

library(DT)
library(shiny)
library(shinyjs)
library(shinydashboard)
library(shinydashboardPlus)

ui <- 
   shinydashboard::dashboardPage(
      shinydashboard::dashboardHeader(),
      shinydashboard::dashboardSidebar(
         shinydashboard::menuItem(
           tabName = NULL,
           icon = shiny::icon("download"),
           text = "Export data set"
         ),
         shiny::tags$div(
           id = "sidebar-table-buttons",  # necessary to reference to in javascript function
           shiny::actionButton("button_export_datatable_csv",
                               label = "csv"),
         )
      ),
      shinydashboard::dashboardBody(
         shinyjs::useShinyjs(),
         shiny::fluidRow(
           shinydashboardPlus::box(
              DT::dataTableOutput("dt_mtcars"),
              width = 12,
              height = 12
           )
         )
      )
   )

server <- 
   function(input, output, session) {  
      output$dt_mtcars =
         DT::renderDataTable(
            DT::datatable(
               mtcars,
               selection = "single",
               editable = FALSE,
               extensions = "Buttons",
               options = list(dom = "Bt",
                              buttons = c("csv"),
                              paging = TRUE
               )
            ),
            server = FALSE
         )
      
      observeEvent(
         input$button_export_datatable_csv,
         JS("$('.buttons-csv').trigger('click');")
      )
   }

shiny::shinyApp(ui, server)

Solution

  • You cannot run JavaScript server-side without sending a message to the client (UI) using session$sendCustomMessage(). Here, we can use the actionButton()'s onclick method to execute the JavaScript without having to use the server at all.

    shiny::actionButton(
      "button_export_datatable_csv",
      label = "csv", 
      # Click the CSV button when the button is pressed
      onclick = "$('.buttons-csv').trigger('click');"
    )
    

    To hide the original button, you can use some CSS.

    tags$head(tags$style(
      rel = "stylesheet",
      ".buttons-csv {
         display: none !important;
       }"
    ))
    

    Here is the full code:

    library(DT)
    library(shiny)
    library(shinyjs)
    library(shinydashboard)
    library(shinydashboardPlus)
    
    ui <- 
      shinydashboard::dashboardPage(
        shinydashboard::dashboardHeader(),
        shinydashboard::dashboardSidebar(
          shinydashboard::menuItem(
            tabName = NULL,
            icon = shiny::icon("download"),
            text = "Export data set"
          ),
          shiny::tags$div(
            id = "sidebar-table-buttons",  # necessary to reference to in javascript function
            shiny::actionButton("button_export_datatable_csv",
                                label = "csv", 
                                # Click the CSV button when the button is pressed
                                onclick = "$('.buttons-csv').trigger('click');"),
          )
        ),
        shinydashboard::dashboardBody(
          # Custom CSS to disable download button
          tags$head(tags$style(
            rel = "stylesheet",
            ".buttons-csv {
              display: none !important;
            }"
          )),
          shinyjs::useShinyjs(),
          shiny::fluidRow(
            shinydashboardPlus::box(
              DT::dataTableOutput("dt_mtcars"),
              width = 12,
              height = 12
            )
          )
        )
      )
    
    server <- 
      function(input, output, session) {  
        output$dt_mtcars =
          DT::renderDataTable(
            DT::datatable(
              mtcars,
              selection = "single",
              editable = FALSE,
              extensions = "Buttons",
              options = list(dom = "Bt",
                             buttons = c("csv"),
                             paging = TRUE
              )
            ),
            server = FALSE
          )
      }
    
    shiny::shinyApp(ui, server)