rhandsontable icon indicating copy to clipboard operation
rhandsontable copied to clipboard

Bug when running rhandsontable in modal dialogue (reference issue # 24)

Open lgirola opened this issue 3 years ago • 4 comments

Hi, rhandsontable is very useful for the types of models I work with. And in combination with modal dialogue, it makes the model input process very user friendly.

However, when an rhandsontable is rendered in a modal box, depending on the circumstance only a part of the table is rendered until the user clicks on the partially rendered table. Is this a bug, or am I using rhandsontable incorrectly? Please see super simple MWE code below. It renders the initial table just fine, but when the user makes a change to the table (for example inserting a row with data) and tries re-rendering it by clicking the "Show" action button, only part of the table is rendered until the user clicks on the table.

The first image shows the rendered table when first invoking the app - looks good. The second image shows the rendered table after having inserted a row/data and then clicking "Show" -- I only get a partial rendering of the table until clicking on it, and then the complete table pops up (as it should have done after the "Show" click). The third images shows the completely and correctly rendered table after inserting a 3rd row, after clicking "Show", and after clicking on the partially rendered table.

library(shiny)
library(rhandsontable)

ui <- fluidPage(actionButton("show", "show"), 
                actionButton("change", "Change"))

server <- function(input, output, session) {
  dat <- reactiveVal(data.frame(x = runif(2), 
                                y = runif(2)))

  dat1 <- reactive({
    if(is.null(input$hot)){
      dat()
    } else {
      as.data.frame(hot_to_r(input$hot))
    }
  })

  observeEvent(input$show, {
    showModal(modalDialog(rHandsontableOutput("hot")))
  })

  observeEvent(input$change, 
               dat(data.frame(x = runif(2), y = runif(2))))

  output$hot <- renderRHandsontable(rhandsontable(dat1()))

}

shinyApp(ui,server)

Image1 Image2 Image3

lgirola avatar Jul 24 '21 14:07 lgirola

Link to related SO-Question: https://stackoverflow.com/questions/68496116/in-r-shiny-how-do-you-reset-data-reversing-all-manual-inputs-in-rhandsontable/

ismirsehregal avatar Jul 27 '21 07:07 ismirsehregal

@ismirsehregal Since the handsontable is rendered into a hidden element, handsontable will not know a size. My solution below makes two changes:

  1. Add some JavaScript to re-render the handsontable on the show.bs.modal event
  2. Change to height: auto; in rHandsontableOutput
library(shiny)
library(rhandsontable)

ui <- fluidPage(
  tags$head(tags$script(HTML(
"
$(document).on('show.bs.modal', function() {
  var w = HTMLWidgets.find('#hot');
  var hot = w && w.hot ? w.hot : null
  if(hot === null) {return null} // if handsontable not defined or rendered then exit
  
  hot.render();
})
"
  ))),
  actionButton("show", "show"), 
  actionButton("change", "Change")
)

server <- function(input, output, session) {
  dat <- reactiveVal(data.frame(x = runif(2), 
                                y = runif(2)))

  dat1 <- reactive({
    if(is.null(input$hot)){
      dat()
    } else {
      as.data.frame(hot_to_r(input$hot))
    }
  })

  observeEvent(input$show, {
    showModal(
      modalDialog(
        {
          # messy way to change height to auto from 100%
          hot <- rHandsontableOutput("hot")
          hot[[1]]$attribs$style <- "height: auto; width: 100%;"
          hot
        }
      )
    )
  })

  observeEvent(input$change, 
               dat(data.frame(x = runif(2), y = runif(2))))

  output$hot <- renderRHandsontable(rhandsontable(dat1(), licenseKey = "non-commercial-and-evaluation"))

}

shinyApp(ui,server)

timelyportfolio avatar Aug 08 '21 14:08 timelyportfolio

Thanks a lot for looking into this @timelyportfolio! Perhaps @jrowen can offer advice on making a more permanent solution, but this works well in my testing.

DillonHammill avatar Aug 08 '21 23:08 DillonHammill

The above post from timelyportfolio does clean up the re-rendering issue noted in the original #387 Issue posting dated Jul-24. However, the "Change" (or "Reset") button doesn't work -- clicking it should revert the output back to a 2 x 2 table of 4 random numbers obviating any manual changes that have been made to the table. Any ideas on how to fix this? As I've dealt with this issue and tried alternative solutions, resolving the re-rendering issue triggers the reset issue, and resolving the reset issue triggers the re-rendering issue. There needs to be a way out of this circle.

lgirola avatar Aug 23 '21 07:08 lgirola