I found an extremely helpful answer here that is almost what I need.
This solution of embedding a selectInput
in a DataTable works great, but not for those with many rows.
The issue is that the function shinyInput()
uses a for
loop that can't keep up with tables with rows greater than 1000. It makes the table run far too slowly.
Generating this many input objects takes time. I will need to trigger an SQL UPDATE
statement after, but that is another issue.
Is there a way to make this run faster, maybe by generating input objects on the fly as the user clicks through pages?
Another issue is that when the table finally does load with all the embedded objects, if you try to change one of the selectInput
's, you will notice that the table takes a long time to catch up.
See this example app:
library(shiny)
library(DT)
DF = matrix(round(rnorm(1000000, mean = 0, sd = 1), 2), ncol = 50)
runApp(list(
ui = basicPage(
h2('A large dataset'),
DT::dataTableOutput('mytable'),
h2("Selected"),
tableOutput("checked")
),
server = function(input, output) {
# Helper function for making checkbox
shinyInput = function(FUN, len, id, ...) {
inputs = character(len)
for (i in seq_len(len)) {
inputs[i] = as.character(FUN(paste0(id, i), label = NULL, ...))
print(i)
}
inputs
}
# Helper function for reading checkbox
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value)) NA else value
}))
}
# Create select input objects to embed in table
Rating = shinyInput(selectInput,
nrow(DF),
"selecter_",
choices=1:5,
width="60px")
# Data frame to display
DF_display = data.frame(DF, Rating)
# Datatable with selectInput
output$mytable = DT::renderDataTable(
DF_display,
selection = 'none',
server = FALSE,
escape = FALSE,
options = list(
paging = TRUE,
pageLength = 20,
lengthMenu = c(5, 10, 20, 100, 1000, 10000),
preDrawCallback = JS('function() {
Shiny.unbindAll(this.api().table().node()); }'),
drawCallback = JS('function() {
Shiny.bindAll(this.api().table().node()); } '))
)
# Read select inputs
output$checked <- renderTable({
data.frame(selected = shinyValue("selecter_", nrow(DF)))
})
}
))
DT
table as alternative. I just realised I posted a similar question about this: #47073466 – Gallopbokeh
, but it didn't convince me. I think here the limiting factor is the shiny/DT combination. If DT where to be a part of shiny it would be easier. However there are always workarounds: I meant that you use filters like here and then theinput$mytable_all_rows
- or theinput$mytable_selected_rows
-property ofDT
. Alternatively you can subset your table with a dropdown. – Gallop