I'm trying to add a "save inputs" feature to my Shiny app where the saved inputs would be saved in a DT data table. If a user clicks an Add button, the inputs would be appended to a data table. A user then can delete a row from this data table by selecting a row and clicking the Delete button. I also need to have this table's values be saved as a global variable so it stays persistent across all sessions.
The example code is shown below. When I close the session, the table (this_table
) is correctly updated, however, those changes don't appear realtime during the app. I've tried putting both of these input buttons in an eventReactive
function, but this did not work when one of the buttons was selected more than once.
Any ideas?
Global table:
this_table = data.frame(bins = c(30, 50), cb = c(T, F))
Shiny app code:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
checkboxInput("cb", "T/F"),
actionButton("add_btn", "Add"),
actionButton("delete_btn", "Delete")
),
mainPanel(
DTOutput("shiny_table")
)
)
)
server <- function(input, output) {
observeEvent(input$add_btn, {
t = rbind(data.frame(bins = input$bins,
cb = input$cb), this_table)
this_table <<- t
})
observeEvent(input$delete_btn, {
t = this_table
print(nrow(t))
if (!is.null(input$shiny_table_rows_selected)) {
t <- t[-as.numeric(input$shiny_table_rows_selected),]
}
this_table <<- t
})
output$shiny_table <- renderDT({
datatable(this_table, selection = 'single', options = list(dom = 't'))
})
}
shinyApp(ui = ui, server = server)
You can use reactiveVal
to add server side variables that are observable and mutable at the same time. The syntax for those variables is to initialize them as
rV <- reactiveValue("init_value")
and update them with
rV("new_value")
Those variables can be accessed inside reactive contexts (basically like input
s) with
rV()
The syntax is quite unusual for R and might take time to get used to, but it is definitely the recommended way to solve issues like these. You might also want to take a look at reactiveValues
for a similar functionality but with a semantic closer to the R class list
.
Here is how this technique can be applied to your question
library(shiny)
library(DT)
this_table = data.frame(bins = c(30, 50), cb = c(T, F))
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
checkboxInput("cb", "T/F"),
actionButton("add_btn", "Add"),
actionButton("delete_btn", "Delete")
),
mainPanel(
DTOutput("shiny_table")
)
)
)
server <- function(input, output) {
this_table <- reactiveVal(this_table)
observeEvent(input$add_btn, {
t = rbind(data.frame(bins = input$bins,
cb = input$cb), this_table())
this_table(t)
})
observeEvent(input$delete_btn, {
t = this_table()
print(nrow(t))
if (!is.null(input$shiny_table_rows_selected)) {
t <- t[-as.numeric(input$shiny_table_rows_selected),]
}
this_table(t)
})
output$shiny_table <- renderDT({
datatable(this_table(), selection = 'single', options = list(dom = 't'))
})
}
shinyApp(ui = ui, server = server)
Finally, I would like to add that @ Vishesh Shrivastavs recommendation to use the rhandsontable
package is also a viable approach, although you will definitely loose some flexibility in doing so.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With