JackAndrew
JackAndrew

Reputation: 5

Save changes to different datatables in Shiny

I'm writing a Shiny app that allows users to view and change multiple data frames. Ultimately, I'd like the changes to overwrite values in the original data frames so that they can be used in a calculation. Below is what I have so far. I've figured out how to allow the user to switch between dataframes, change values for the dfs, and "reset" the changes to the original values for df1 and df2. But I'd like to add an observeEvent that overwrites df1 and df2 with user changes.

library(shiny)
library(DT)
df1 <- data.frame(a = c('a','b','c','d','e'), 
                  b = round(rnorm(5, 0,1),2))
df2 <- data.frame(a = c('a','b','c','d','e'), 
                  b = round(rnorm(5, 1,1.5),2))

ui <- fluidPage(
  titlePanel("example"),
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "df",
                  label = "Choose a table:",
                  choices = c("df1", 
                              "df2")),
    ),
    mainPanel(
      actionButton("reset", "Reset"),
      actionButton("save", "Save Changes"),
      DTOutput("df")

      )
    )
  )
server <- function(input, output) {
  dfInput <- reactive({
    switch(input$df,
           "df1" = df1,
           "df2" = df2)
  })

  observeEvent(input$reset, {
    output$df <- renderDT(dfInput(), editable = TRUE,
                          options = list(lengthChange = FALSE))
  })

  output$df <- renderDT(dfInput(), editable = TRUE,
                        options = list(lengthChange = FALSE))
}
shinyApp(ui = ui, server = server)

Thanks!

Upvotes: 0

Views: 300

Answers (1)

Ben
Ben

Reputation: 30494

One possible solution is to use observeEvent and record any edits made in real-time, instead of waiting for user to hit save button. If that approach works for you, then this might be helpful.

Note that you only need one output instead of two, and that reset will automatically revert to original data. To do this, you can use reactiveValues to store your data. In this case, I made a list of two data frames for df1 and df2.

Also, to allow for testing with edits in this example, I added stringsAsFactors = FALSE to your two data.frames when created (so edits not limited to factor levels).

library(shiny)
library(DT)

df1 <- data.frame(a = c('a','b','c','d','e'), 
                  b = round(rnorm(5, 0,1),2),
                  stringsAsFactors = F)
df2 <- data.frame(a = c('a','b','c','d','e'), 
                  b = round(rnorm(5, 1,1.5),2),
                  stringsAsFactors = F)

ui <- fluidPage(
  titlePanel("example"),
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "df",
                  label = "Choose a table:",
                  choices = c("df1", 
                              "df2")),
    ),
    mainPanel(
      actionButton("reset", "Reset"),
      #actionButton("save", "Save Changes"),
      DTOutput("df")          
    )
  )
)

server <- function(input, output) {
  rv <- reactiveValues(tables = list("df1" = df1, "df2" = df2))

  dfInput <- reactive({
    rv$tables[[input$df]]
  })

  observeEvent(input[["df_cell_edit"]], {
    cell <- input[["df_cell_edit"]]
    rv$tables[[input$df]][cell$row, cell$col] <- cell$value
  })

  observeEvent(input$reset, {
    rv$tables <- list("df1" = df1, "df2" = df2)
  })

  output$df <- renderDT(dfInput(), editable = TRUE,
                        options = list(lengthChange = FALSE))
}

shinyApp(ui = ui, server = server)

Upvotes: 0

Related Questions