How to save edits made using rhandsontable r package

Viewed 3188

My R program works as expected. It shows a table containing my dataFrame, and lets me edit the values.

How do I capture those values and save them to my dataframe, or a copy of my dataframe?

require(shiny)
library(rhandsontable)

    DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
                    small = letters[1:10],
                    dt = seq(from = Sys.Date(), by = "days", length.out = 10),
                    stringsAsFactors = F)

    rhandsontable(DF, rowHeaders = NULL)

EDIT: The above code produces a table with rows and columns. I can edit any of the rows and columns. But when I look at my dataFrame, those edits do not appear. What I am trying to figure out is what do I need to change so I can capture the new values that were edited.

5 Answers

I know this thread's been dead for years, but it's the first StackOverflow result on this problem.

With the help of this post - https://cxbonilla.github.io/2017-03-04-rhot-csv-edit/, I've come up with this:

library(shiny)
library(rhandsontable)

values <- list() 

setHot <- function(x) 
  values[["hot"]] <<- x 

DF <- data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
                small = letters[1:10],
                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
                stringsAsFactors = FALSE)


ui <- fluidPage(
  rHandsontableOutput("hot"),
  br(),
  actionButton("saveBtn", "Save changes")
)

server <- function(input, output, session) {

  observe({
    input$saveBtn # update dataframe file each time the button is pressed
    if (!is.null(values[["hot"]])) { # if there's a table input
      DF <<- values$hot
    }
  })

  observe({
    if (!is.null(input$hot)){
      DF <- (hot_to_r(input$hot))
      setHot(DF)
    } 
  })


  output$hot <- renderRHandsontable({ 
    rhandsontable(DF) %>% # actual rhandsontable object
      hot_table(highlightCol = TRUE, highlightRow = TRUE, readOnly = TRUE) %>%
      hot_col("big", readOnly = FALSE) %>%
      hot_col("small", readOnly = FALSE)
  })

}

shinyApp(ui = ui, server = server)

However, I don't like my solution on the part of DF <<- values$hot as I previously had problems with saving changes to the global environment. I've couldn't figure it out any other way, though.

It seems to be accessible now via input$NAME_OF_rHandsontableOutput and can be converted to a data.frame via hot_to_r().

Reproducible example:

library(shiny)
library(rhandsontable)

ui <- fluidPage(
  rHandsontableOutput("hottable")  
)

server <- function(input, output, session) {
  observe({
    print(hot_to_r(input$hottable))
  })
  
  output$hottable <- renderRHandsontable({
    rhandsontable(mtcars)
  })
}

shinyApp(ui, server)

I was able to accomplish this with a more simple solution for saving data while the app is open and after it is closed for shiny 1.7++

Create an observe event dependent upon a save button clicked at any point when the app is open. I've scaled this method in more complex apps where you have a selectizeinput for swapping in and out different data frames into the rhandsontable, each of which are edited, saved and recalled while the app is open.

In the server:

   observeEvent(input$save, { #button is the name of the save button, change as needed
    df <<- hot_to_r(input$rhandsontable) #replace rhandsontable with the name of your own
    }) #df is the data frame that have it access when the app starts

In the UI:

actionButton("save","Save Edits")

If you are using Shiny then input$table$changes$changes can give you the edited value with row and column index. Below is the code if you want to update only specific cell and not the complete table using hot_to_t().

library(shiny)
library(rhandsontable)

DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
                small = letters[1:10],
                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
                stringsAsFactors = F)



ui <- fluidPage(
  rHandsontableOutput('table')
)

server <- function(input, output) {
  
  X = reactiveValues(data = DF)

  output$table <- rhandsontable::renderRHandsontable({
    rhandsontable(X$data, rowHeaders = NULL)
  })
  
  observeEvent(input$table$changes$changes,{
    row = input$table$changes$changes[[1]][[1]]
    col = input$table$changes$changes[[1]][[2]]
    value = input$table$changes$changes[[1]][[4]]
    
    X$data[row,col] = value
})
}

shinyApp(ui, server)
Related