How can I stop rhandsontable from starting an infinite loop after inputs in quick succession?

Viewed 48

I'm using rhandsontable in a shiny app to manually update a dataframe to be displayed with ggplot2.

When adding/changing values in the rhandsontable in quick succession, the table starts an infinite loop, which immobilizes the entire shiny application.

Below an example. By quickly changing the values in the table, the app gets stuck.

library(shiny)
library(rhandsontable)
library(ggplot2)

ui <- fluidPage(
  rHandsontableOutput("hot"),
  plotOutput("plot")
)

server <- function(input, output, session) {
  
  reactive.table <- reactiveValues(values = data.frame(x = c(1,2), y = c(1,2)))
  
  observe({
    if (!is.null(input$hot)) {
      reactive.table$values <<- hot_to_r(input$hot)
    }
  })
  
  output$hot <- renderRHandsontable({
    rhandsontable(reactive.table$values)
  })
  
  output$plot <- renderPlot({
    Sys.sleep(2)
    ggplot(reactive.table$values, aes(x = x, y = y)) +
      geom_point()
  })
  
}

shinyApp(ui = ui, server = server)

Is there a way to stop the infinite loop or to disable further inputs until the plot is rendered? Thanks.

1 Answers

I don't know how to stop rhandsontable from starting the infinite loop, but you can avoid inputs in quick succession altogether.

Taking your reprex, I restrict changes to be at least 1 second apart, and it works just fine.

library(shiny)
library(rhandsontable)
library(ggplot2)

ui <- fluidPage(
  rHandsontableOutput("hot"),
  plotOutput("plot")
)

server <- function(input, output, session) {
  
  reactive.table <- reactiveValues(values = data.frame(x = c(1,2), y = c(1,2)))
  
  rv_timer <- reactiveValues(
    prev = NULL, current = NULL
  )
  
  observe({
    if (!is.null(input$hot)) {
      # if it's first time editing table:
      if (is.null(rv_timer$prev)) {
        rv_timer$prev <- Sys.time()
        reactive.table$values <- hot_to_r(input$hot)
        return(NULL)
      }
      
      # if it's not the first time to edit table, get current clock time:
      rv_timer$current <- Sys.time()
      
      # if the difference btwn prev recorded time and current time is less 
      # than 1second, don't do anything, just return:
      if ((rv_timer$current - rv_timer$prev) < 1) {
        return(NULL)
      }
      
      # otherwise proceed as normal:
      reactive.table$values <- hot_to_r(input$hot)
      
      # finally set current clock time as `rv_timer$prev` for use in the next 
      # invalidation:
      rv_timer$prev <- Sys.time()
    }
  })
  
  output$hot <- renderRHandsontable({
    rhandsontable(reactive.table$values)
  })
  
  output$plot <- renderPlot({
    Sys.sleep(2)
    ggplot(reactive.table$values, aes(x = x, y = y)) +
      geom_point()
  })
  
}

shinyApp(ui = ui, server = server)

Might be a bug in {rhansontable}.

Related