rshinymodal-dialogrhandsontableshowmodaldialog

ID for rhandsontable inside modal in R Shiny


My goal is to display an (conditional) editable rhandsontable inside a modal by clicking an actionbutton. Creating and displaying the table worked fine, however I'm struggling on how to properly assign an ID in the ui for the table in order to recognize user changes.

Any help is appreciated, thank you :)

library(shiny)

ui <- fluidPage(
  actionButton('openModal', "Open Modal")
  # rHandsontableOutput("DataEditor") # doesn't work
)

server <- function(input, output, session) {
  
  observeEvent(input$openModal, {
    irrelevant_condition <- FALSE # include that rhandsontable doesn't have to appear always
    if (irrelevant_condition == TRUE) {
      return(showModal(modalDialog("Choose some variables to display first")))
    } else {
      # display rhandsontable if user made a valid choice
      showModal(modalDialog(  
        updDataEditor()
      ))
    }
  })
  
  updDataEditor <- function() {
    output$DataEditor <- renderRHandsontable({
      # in real app some conditional calculations leading to a DF called 'current.DF'
      # why function?: in real app with variation, depending on some inputs the user chose
      current.DF <- data.frame(Name = c("Name1", "Name2"), value1 = c(0,0), value2=c(0,0)) # example df
      rhandsontable(current.DF) 
    })
  }
    
  observeEvent(input$DataEditor, {
    # Here's the problem
    # won't get called when DataEditor is modified by the user
    browser() 
    return()
  })
  
}
shinyApp(ui,server)

Solution

  • This works like this:

    library(shiny)
    library(rhandsontable)
    
    ui <- fluidPage(
      actionButton('openModal', "Open Modal")
    )
    
    server <- function(input, output, session) {
      
      current.DF <- reactive(
        data.frame(Name = c("Name1", "Name2"), value1 = c(0,0), value2=c(0,0))
      )
      
      observeEvent(input$openModal, {
        irrelevant_condition <- FALSE # include that rhandsontable doesn't have to appear always
        if (irrelevant_condition == TRUE) {
          return(showModal(modalDialog("Choose some variables to display first")))
        } else {
          # display rhandsontable if user made a valid choice
          showModal(modalDialog(  
            rHandsontableOutput("DataEditor")
          ))
        }
      })
      
      output$DataEditor <- renderRHandsontable({
        rhandsontable(current.DF()) 
      })
      
      observeEvent(input$DataEditor, {
        print(input$DataEditor$changes)
      })
      
    }
    shinyApp(ui,server)
    

    Is it what you want? For the dataframe which can change I would use a reactive value. If only some cells are changed you can use the set_data function, better.


    EDIT Solving the problem raised in the comments:

      output$DataEditor <- renderRHandsontable({
        rhandsontable(current.DF()) %>% htmlwidgets::onRender(
          "function(el){var hot = this.hot; setTimeout(function(){hot.render();}, 1000)}"
        )
      })