I am trying to create a dynamic table in shiny using reactable where any time "Sell" is selected in a given row in the transaction column, the corresponding row in the quantity column changes to zero.
I am able to generate a selectInput in any row, but I am having trouble changing the value in the quantity column after the fact. I assume I can do this with some combination of observe/observeEvent and updateReactable but have not been able to solve it myself. Here is what I have tried:
library(shiny)
library(tidyverse)
library(reactable)
df <- tibble(
rowId = 1:5,
fruit = c("apple", "banana", "orange", "kiwi", "grape"),
quantity = c(10, 20, 15, 5, 12)) %>%
group_by(rowId) %>%
mutate(transaction = as.character(selectInput(inputId = rowId,
label = NULL,
choices = c("Keep", "Sell")))) %>%
ungroup()
ui <- fluidPage(
titlePanel("Fruit Table"),
mainPanel(
reactableOutput("table")
)
)
# Server----
server = function(input, output, session) {
# Team Budget Table----
fruit_table <- reactive({
df_reactable <- reactable(
df,
defaultColDef = colDef(
align = "center",
width = 100,
headerStyle = list(background = "#ededed", fontSize = 11),
style = function(value) {
list(fontSize = 11,
height = 25)
}
),
columns = list(
transaction = colDef(
html = T
)
),
bordered = T,
highlight = T,
fullWidth = F,
pagination = F
)
df_reactable
})
output$table <- renderReactable(fruit_table())
observeEvent(input$rowId, {
df[input$rowId, "quantity"] <- ifelse(input[[input$rowId]] == "Sell", 0, df[input$rowId, "quantity"])
})
}
EDIT:
With some help from YBS, I was able to get this sort of working. When I select "Sell" in a given row, the table changes the quantity column in that row to 0. However, the issue I still have is that when a new row is set to "Sell", the original row (which was set to "Sell") reverts back to its original quantity rather than staying at zero. The documentation on updateReactable says "When updating data
, the selected rows, expanded rows, and current page
will reset unless explicitly specified." So it does seem to be possible.
Updated code:
library(shiny)
library(tidyverse)
library(reactable)
js <- "
$(document).on('shiny:value', function(e) {
if(e.name === 'table'){
setTimeout(function(){Shiny.bindAll(document.getElementById('table'))}, 0);
}
});
"
df <- tibble(
rowId = 1:5,
fruit = c("apple", "banana", "orange", "kiwi", "grape"),
quantity = c(10, 20, 15, 5, 12)) %>%
group_by(rowId) %>%
mutate(transaction = as.character(selectInput(inputId = rowId,
label = NULL,
choices = c("Keep", "Sell")))) %>%
ungroup()
ui <- fluidPage(
tags$head(tags$script(js)),
titlePanel("Fruit Table"),
mainPanel(
reactableOutput("table"),
textOutput("selection")
)
)
# Server----
server = function(input, output, session) {
# Create the reactive table
df_reactable <- reactive({
reactable(
df,
defaultColDef = colDef(
align = "center",
width = 100,
headerStyle = list(background = "#ededed", fontSize = 11),
style = function(value) {
list(fontSize = 11,
height = 25)
}
),
columns = list(
transaction = colDef(html = TRUE)
),
bordered = TRUE,
highlight = TRUE,
fullWidth = FALSE,
pagination = FALSE
)
})
# Render the table
output$table <- renderReactable(df_reactable())
lapply(1:nrow(df), function(i) {
observe({
print(i)
filtered <- if (length(input[[paste0(i)]]) > 0) {
df <- df %>%
mutate(quantity = ifelse(input[[paste0(i)]] == "Sell" &
row_number() == paste0(i),
0, quantity))
} else {
df
}
updateReactable(outputId = "table",
data = filtered)
})
})
}
shinyApp(ui = ui, server = server)