javascriptrshinydt

How to get the mouse click location within a scrollable datatable?


Is it possible for showNotification() to pop up at the location the mouse was clicked? More specifically, I have a table and I want an actionButton to pop-up near each clicked row.

Here is a reproducible example:

library(shiny)
library(DT)

ui <- fluidPage(
    tags$script(HTML("
    $(document).on('click', 'table tbody tr', function(e) {
      Shiny.setInputValue('click_coords', {x: e.pageX, y: e.pageY}, {priority: 'event'});
    });

    Shiny.addCustomMessageHandler('adjustNotifPosition', function(message) {
      $('.shiny-notification').css({
        'top': message.y + 'px',
        'left': message.x + 'px'
      });
    });
  ")),
    
    tags$style(HTML("
    .shiny-notification {
      width: 250px;
      height: auto;
      position: fixed;
      background-color: #FFD700;   /* Gold background */
      color: black;
      font-weight: bold;
      border: 2px solid black;
      border-radius: 15px;
      padding: 10px;
      text-align: center;
    }
  ")),
    
    DT::dataTableOutput('summary_table')
)

server <- function(input, output, session) {
    
    data <- data.frame(
        ID = 1:1000,
        Value = rnorm(1000)
    )
    
    output$summary_table <- DT::renderDataTable({
        datatable(data, selection = 'single')
    }, server = FALSE)
    
    observeEvent(input$click_coords, {
        if (!is.null(input$summary_table_rows_selected)) {
            selected_row <- input$summary_table_rows_selected
            
            # Show the notification
            showNotification(
                paste("You selected row number", selected_row),
                closeButton = TRUE,
                duration = NULL,
                action = actionButton("go_to_figure_tables", "Go to Figure Tables"),
                id = "notif"
            )
            
            x_coord <- input$click_coords$x
            y_coord <- input$click_coords$y
            # Adjust its position
            session$sendCustomMessage('adjustNotifPosition', list(x = x_coord, y = y_coord))
        }
    })
    
    observeEvent(input$go_to_figure_tables, {
        # Handle the action here
        print("Go to Figure Tables button clicked!")
        removeNotification(id = "notif") 
    })
}

shinyApp(ui, server)

It works okay but if I set the number of entries large enough to have to scroll down, the pop-up doesn't show at the proper place.


Solution

  • If you want to get the correct position also when your table is scrollable, you have to subtract $(document).scrollLeft() from e.pageX and $(document).scrollTop() from e.pageY.

    $(document).on('click', 'table tbody tr', function(e) {
        Shiny.setInputValue('click_coords', {
            x: e.pageX - $(document).scrollLeft(),
            y: e.pageY - $(document).scrollTop()
        }, {
            priority: 'event'
        });
    });
    

    enter image description here