0

I have an R shiny app where I want to display a table as a reactable object. There I want to have a filter functionality that provides more functionality than the standard filters for reactable objects that appear when I set filterable = TRUE in reactable. For example I want to be able to filter multiple entries in a column containing categorical values (strings or factors), very much like in the selectInput function. The second thing I want to do is to change values of selected rows.

The first solution I tried was to use the crosstalk package that allows to create a shared data object which I implemented as in the following minimal working example.

library(shiny)
library(reactable)

ui <- fluidPage(

    mainPanel(
           uiOutput("ui_display")
        )
)

server <- function(input, output) {

    session_data <- reactiveValues(
      data_to_display = NULL
    )
    
    observe({
      session_data$data_to_display <- data.table::data.table("a" = 1:1e5,
                                                 "b" = sample(letters, 1e5, replace = TRUE))
    })
    
    display_table_shared_underlying_data <- crosstalk::SharedData$new(
      reactive({
        session_data$data_to_display
      })
    )
    
    output$display_table <- reactable::renderReactable({
      req(display_table_shared_underlying_data)
      display_table_shared_underlying_data %>%
        reactable::reactable(.,
                             onClick = "select",
                             selection = "multiple",
                             striped = TRUE)
    })
    
    display_table_rows_selected <- reactive({
      reactable::getReactableState("display_table", "selected")
    })
    
    output$ui_display <- renderUI({
      fluidPage(
        fluidRow(
          reactableOutput("display_table")
        ),
        fluidRow(
          column(3,
                 actionButton("change_btn", "Change column b value in the selected row")),
          column(3,
                 crosstalk::filter_select("b", 
                                          "b",
                                         display_table_shared_underlying_data, ~b))
        )
      )
    })
    
    observeEvent(
      input$change_btn,
      {
        selected_rows_id <- display_table_rows_selected()
        session_data$data_to_display$b[selected_rows_id] <-
          "z"
      })
}

# Run the application 
shinyApp(ui = ui, server = server)

This comes very close to the behaviour I want to get. But I have the following problem: After changing the value of any row by clicking on "Change column b value in the selected row" the table shows initially only the rows that have been changed. However, after clicking one of these rows all the other rows appear again. This is highly undesired but even worse: Selecting all rows gets really slow after a value was changed and takes several seconds. The size of the table cannot be decreased as the data I consider has in some cases far more than 100000 rows. Does anyone know what causes this behaviour?

The second solution I tried was to use the shinyfilter package as in the example here. However, the selectizeInput function reacts instantaneously when I click on a certain value (for example when I select a specific manufacturer in the app provided in the link) so that it is impossible to select multiple values, although multiple = TRUE. I thought that update_tooltips might provide a solution but I don't see what this does in the app.

So if anyone knows how to fix the undesired behaviours in my approaches or how to get the behaviour I want by using reactable (with DT I know how do this but this has other drawbacks I want to get rid of by using reactable) I would really appreciate it!

jfiedler
  • 43
  • 4

0 Answers0