I have a shiny dashboard where the tables are created with the reactable
package. I have simple and nested tables and as far as I can see, there is only a download option for csv:
library(htmltools)
library(fontawesome)
data <- MASS::Cars93[1:15, c("Manufacturer", "Model", "Type", "Price")]
htmltools::browsable(
tagList(
tags$button(
tagList(fontawesome::fa("download"), "Download as CSV"),
onclick = "Reactable.downloadDataCSV('cars-download-table', 'cars.csv')"
),
reactable(
data,
searchable = TRUE,
defaultPageSize = 5,
elementId = "cars-download-table"
)
)
)
I want to create one Excel download file with the following attributes:
checkboxGroupInput
The problem is, that I want to use the data shown in the reactable
(e.g. the selected columns), therefore I can not use the raw data. Is there some kind of package I can use?
So far, I only have a slow solution where I put the reactable
into an additional variable before I render the table and then I read the data from this variable and use the package openxlsx
to write the Excel.
Here is a clue. You can get the current state of the table with Reactable.getState
, and the current display is in the field sortedData
. This is demonstrated by the app below.
library(shiny)
library(reactable)
library(jsonlite)
registerInputHandler(
"xx",
function(data, ...){
fromJSON(toJSON(data))
},
force = TRUE
)
ui <- fluidPage(
fluidRow(
column(
7,
tags$button(
"Get data",
onclick = '
var state = Reactable.getState("cars");
Shiny.setInputValue("dat:xx", state.sortedData);
'
),
reactableOutput("cars")
),
column(
5,
verbatimTextOutput("data")
)
)
)
server <- function(input, output){
output$cars <- renderReactable({
reactable(MASS::Cars93[, 1:5], filterable = TRUE)
})
output$data <- renderPrint({
input$dat
})
}
shinyApp(ui, server)
Here is an example of downloading the current display:
library(shiny)
library(shinyjs)
library(reactable)
library(jsonlite)
registerInputHandler(
"xx",
function(data, ...){
fromJSON(toJSON(data))
},
force = TRUE
)
ui <- fluidPage(
useShinyjs(),
br(),
conditionalPanel(
"false", # always hide the download button, because we will trigger it
downloadButton("downloadData") # programmatically with shinyjs
),
actionButton(
"dwl", "Download", class = "btn-primary",
onclick = paste0(
'var state = Reactable.getState("cars");',
'Shiny.setInputValue("dat:xx", state.sortedData);'
)
),
br(),
reactableOutput("cars")
)
server <- function(input, output, session){
output$cars <- renderReactable({
reactable(MASS::Cars93[, 1:5], filterable = TRUE)
})
observeEvent(input$dat, {
runjs("$('#downloadData')[0].click();")
})
output$downloadData <- downloadHandler(
filename = function() {
paste0("data-", Sys.Date(), ".xlsx")
},
content = function(file) {
openxlsx::write.xlsx(input$dat, file)
}
)
}
shinyApp(ui, server)