Search code examples
javascriptrshinyhandsontablerhandsontable

Register callback to afterOnCellMouseDown event with rhandsontable


I have an rhandsontable and wish to trigger an event each time a cell is clicked, such that I can identify the cell which was clicked.

From what I've seen, this can only be done using JS.

I've tried using the basic .click() event, but that uses an argument-free function and this is the HTML itself, with no "selectedCell" property or what have you.

library(shiny)
library(shinyjs)
library(rhandsontable)

ui <- fluidPage(
  useShinyjs(),
  actionButton("redraw", "Redraw"),
  rHandsontableOutput("test")
)

server <- function(input, output, session) {
  output$test <- renderRHandsontable({
    input$redraw  # force re-rendering if desired
    
    runjs("$('#test').click(function() {
          console.log(this)
    });")
    
    rhandsontable(data.frame(a = 1:2, b = 3:4))
  })
}

shinyApp(ui, server)

Looking at the handsontable documentation, I've found the afterOnCellMouseDown event, which seems adequate for my use-case, taking a function with a coords argument which informs me of the selected cell. I should be able to use this in conjunction with Shiny.onInputChange to let my app identify the clicked cell.

However, I can't figure out the JS I need to run to bind to the afterOnCellMouseDown event. As I mentioned, using $('#test') gives me the HTML and I don't know how to access the hot itself.


Solution

  • With the app below, the coordinates of the clicked cell are sent to input$clickedCell, a list of the form list(row = i, col = j).

    library(shiny)
    library(rhandsontable)
    library(htmlwidgets)
    
    jsCode <- c(
      "function(el, x) {",
      "  Handsontable.hooks.add('afterOnCellMouseDown', function(event, coords, TD){",
      "    Shiny.setInputValue('clickedCell', coords, {priority: 'event'});",
      "  });",
      "}"
    )
    
    ui <- fluidPage(
      rHandsontableOutput("test")
    )
    
    server <- function(input, output, session) {
      output$test <- renderRHandsontable({    
        rhandsontable(data.frame(a = 1:2, b = 3:4)) %>% onRender(jsCode)
      })
      observe({print(input$clickedCell)})
    }
    
    shinyApp(ui, server)
    

    This is applied to all handsontable instances of the app. I don't know how to target a specific one (I think this is not possible).