rshinyrhandsontable

Edit RHandsonTable After Uploading a File


I've built an R-shiny application that allows users to either manually type data into an RHandsonTable or to upload a csv file. Independently, these work just fine. However, I'm unable to get changes to stick if the user first uploads a file, then tries to edit the table manually.

If you run the example below you'll see that if you check some boxes and hit the "Go" button then the Boolean values are correctly displayed in the output table. Similarly, if you upload a simple csv file (example file also below) and hit "Go" then the Booleans are correctly displayed in the output table. But, if you upload a file then try to check or uncheck the boxes they immediately revert to the uploaded values and will only display the uploaded values until the app is restarted. Any ideas for how to recode this so that it can handle the upload and then allow users to edit that upload?

MRE:

library(shiny)
library(rhandsontable)
library(shinythemes)
library(data.table)

ui <- fluidPage(
  actionButton("go", "Go"),
  fileInput('file',label=''),
  rHandsontableOutput('table1'),
  tableOutput('table2')
)

DF1 <- data.frame(col1 = rep(F,3),col2 = rep(F,3))

server <- function(input, output, session) {
  values <- reactiveValues()
  
  observe({
    if (!is.null(input$table1)) {
      DF1 <- hot_to_r(input$table1)
    } else {
      if (is.null(values$DF1))
        DF1 <- DF1
      else
        DF1 <- values$DF1
    }
    values$DF1 <- DF1
  })
  
  output$table1 <- renderRHandsontable({
    if (!is.null(input$file)){
      inputfile <- fread(input$file$datapath)
      values$DF1 <- inputfile
      rhandsontable(values$DF1)
    } else {
      if (!is.null(values$DF1)) rhandsontable(values$DF1)
    }
  })
  
  observeEvent(input$go,{values$DF2<-values$DF1})
  output$table2 <- renderTable(values$DF2)
}

shinyApp(ui, server)

For a simple file to upload, a csv like so proves the point:

col1,col2

TRUE,FALSE

FALSE,TRUE

TRUE,FALSE


Solution

  • Inside renderRHandsontable() you check if (!is.null(input$file)) and if this is true, the values for the rhandsontable are taken from the input file. However, the condition is always fulfilled after an upload and therefore the table can't be edited anymore after an upload.

    Instead, you could take this away from the renderRHandsontable and put it inside an observeEvent on input$file which replaces the values for the table once when an upload is done (this event just fires once after an upload):

    library(shiny)
    library(rhandsontable)
    library(shinythemes)
    library(data.table)
    
    ui <- fluidPage(
      actionButton("go", "Go"),
      fileInput('file', label = ''),
      rHandsontableOutput('table1'),
      tableOutput('table2')
    )
    
    DF1 <- data.frame(col1 = rep(F, 3), col2 = rep(F, 3))
    
    server <- function(input, output, session) {
      values <- reactiveValues()
      
      observe({
        if (!is.null(input$table1)) {
          DF1 <- hot_to_r(input$table1)
        } else if (is.null(values$DF1)){
            DF1 <- DF1
        }
        values$DF1 <- DF1
      })
      
      observeEvent(input$file, {
        inputfile <- fread(input$file$datapath, drop = 1)
        values$DF1 <- inputfile
      })
      
      output$table1 <- renderRHandsontable({
        req(values$DF1)
        rhandsontable(values$DF1)
      })
      
      observeEvent(input$go, {
        values$DF2 <- values$DF1
      })
      output$table2 <- renderTable(values$DF2)
    }
    
    shinyApp(ui, server)