[Bug]: dropdown_extra() keeps values in memory even if reactable source data changes
Guidelines
- [X] I agree to follow this project's Contributing Guidelines.
Project Version
0.2.0
Platform and OS Version
No response
Existing Issues
No response
What happened?
if a value is changed using dropdown_extra(), then the value persist on the table even if the source data of my reactable changes.
Steps to reproduce
- Create a reactable with dropdown_extra() and with a data source that can change.
- Modify some values with dropdown
- Change data source and see that changes from step 2 persist
Expected behavior
I was expecting these values to be "flushed" when the data changes. Or maybe a mechanism to force the refresh
Attachments
library(shiny)
library(reactable)
library(reactable.extras)
df1 <- MASS::Cars93[1:4, 1:3]
df2 <- MASS::Cars93[5:8, 1:3]
shinyApp(
ui = fluidPage(
reactable_extras_dependency(),
selectInput("data", "Data", c("df1", "df2")),
reactableOutput("react"),
),
server = function(input, output) {
df <- reactive({
if (input$data == "df1") {
df1
} else {
df2
}
})
output$react <- renderReactable({
reactable(
df(),
columns = list(
Type = colDef(
cell = dropdown_extra(
id = "dropdown",
choices = levels(df()$Type),
class = "dropdown-extra"
)
)
)
)
})
}
)
Screenshots or Videos
https://github.com/Appsilon/reactable.extras/assets/46813298/a32c4476-4852-4a91-b82d-31e53ee7bf7a
In this example I changed the values "Type" to "Van" on the first 2 lines in df1. When I switch to df2, the 2 first lines have a "Van" "Type" which is not the case in the dataset.
Additional Information
No response
Seems to be linked to changes made here: 75d8f58a7417826af62bfef80124a81d20d9dbe5 to keep input changes when using pagination.
I second this.
I have run into similar issue, you can force reactable.extras to reset the values by setting global variable called memory to empty object in browser console, so depending on your context you need to run something like:
shinyjs::runjs("memory = {};")
Additional note: in order to properly flush the values you will need to re-render the whole table (so renderReactable will need to run), the updateReactable function does not work with this trick and inputs hold the values anyway.
I will give this suggestion a shot and keep my fingers crossed. I would be great if this issue was properly fixed however. My gut tells me that this should be a fairly easy fix.
I can confirm that shinyjs::runjs("memory = {};") fix the problem about the state of the table.
Here is a reprex. There is one changing-table on the left (call it "base table"); we add rows at the end of it or remove a random row with the buttons. On the right, the modified table is rendered with check inputs. Every time you click on a check, it update the modified table and re-renders it. Below is a print of the modified table.
library(shiny)
library(shinyjs)
library(dplyr)
library(reactable)
library(reactable.extras)
ui <- fluidPage(
reactable.extras::reactable_extras_dependency(),
shinyjs::useShinyjs(),
actionButton(inputId = "add", label = "Add row"),
actionButton(inputId = "delete", label = "Delete row"),
fluidRow(
column(
width = 6
,h2('Base table')
,reactableOutput(outputId = "base"),
)
,column(
width = 6
,h2('Table with inputs')
,reactableOutput(outputId = "table")
)
),
fluidRow(
column(
width = 12
,h2('Modified table (updated from inputs)')
,reactableOutput(outputId = "modified")
)
)
)
server <- function(input, output, session) {
initial_table = tibble(id = 1, ok = FALSE)
rv = reactiveValues(table = initial_table, modified_table = initial_table)
# add a row at the end
observe({
n = if (nrow(rv$table) == 0) 0 else max(rv$table$id)
rv$table =
bind_rows(
rv$table,
tibble(id = n + 1, ok = FALSE)
)
}) |>
bindEvent(input$add)
# delete a random row
observe({
if (nrow(rv$table) == 0) return(NULL)
id = sample(x = 1:nrow(rv$table), size = 1)
rv$table = rv$table[-id, ]
}) |>
bindEvent(input$delete)
# render the table modified table
output$base = renderReactable({
rv$table |> reactable()
})
# modify the table based on the inputs
observe({
req(rv$table)
rv$modified_table =
bind_rows(
inner_join(rv$modified_table, rv$table |> select(id), by = 'id')
,anti_join(rv$table, rv$modified_table |> select(id), by = 'id')
) |>
distinct(id, .keep_all = TRUE) |>
arrange(id)
}) |> bindEvent(rv$table)
observe({
change = input$check
rv$modified_table$ok[change$row] = change$value
print(change)
shinyjs::runjs("memory = {};")
}) |>
bindEvent(input$check)
output$table = renderReactable({
rv$modified_table |>
reactable(
columns = list(
ok = colDef(
cell = checkbox_extra("check", class = "checkbox-extra"),
align = "left"
)
)
)
})
output$modified = renderReactable({
rv$modified_table |> reactable()
})
}
shinyApp(ui, server)
https://github.com/user-attachments/assets/e68e602b-65ab-4223-a222-cce6c8651435