glin / reactable

Interactive data tables for R
https://glin.github.io/reactable
Other
627 stars 80 forks source link

Ignore propagation of cell click on internal element in cell #313

Closed dleopold closed 1 year ago

dleopold commented 1 year ago

I am trying to figure out how to retain row selection as the cell click action for the entire table, but not when clicking on a particular element within a cell. In the following toy example I am using a custom cell rendering function to add an onclick action to the text in the 'Species' column of the iris data set. I know I could use a custom on click function for the table to select the row only if clicking in any column other than 'Species'. However, I would like to retain the row selection for all cells, just not when specifically clicking the tag element within the 'Species' cell.

library(shiny)
library(reactable)

ui <- fluidPage(reactable::reactableOutput('table') )

server <- function(input, output) {

  table <- reactive({ iris })

  output$table <- reactable::renderReactable({
    reactable(
      table(),
      selection = "multiple",
      onClick = "select",
      columns=list(
        Species=colDef(
          html = TRUE,
          cell = htmlwidgets::JS(
            "function(cellInfo) {
                var spp = cellInfo.value;
                return `<a id=${spp} ` +
                `onclick='Shiny.onInputChange(&#39;clickaction&#39;, this.id.concat(&quot;_&quot;, Math.random()))'>` +
                cellInfo.value +
                `</a>`;
                }"
          )
        )
      )
    )
  })
  observeEvent(input$clickaction, {print(input$clickaction)})
}

shinyApp(ui = ui, server = server)
glin commented 1 year ago

Hi, you can call event.stopPropagation() anywhere in the event handler to prevent the click event from bubbling up beyond the element and triggering the row selection. Here's a slight modification of the example to do that:

library(shiny)
library(reactable)

ui <- fluidPage(reactable::reactableOutput('table') )

server <- function(input, output) {

  table <- reactive({ iris })

  output$table <- reactable::renderReactable({
    reactable(
      table(),
      selection = "multiple",
      onClick = "select",
      columns=list(
        Species=colDef(
          html = TRUE,
          cell = htmlwidgets::JS(
            "function(cellInfo) {
                var spp = cellInfo.value;
                return `<a id=${spp} href='#'` +
                `onclick='event.stopPropagation(); Shiny.onInputChange(&#39;clickaction&#39;, this.id.concat(&quot;_&quot;, Math.random()))'>` +
                cellInfo.value +
                `</a>`;
                }"
          )
        )
      )
    )
  })
  observeEvent(input$clickaction, {print(input$clickaction)})
}

shinyApp(ui = ui, server = server)

As a side note, I also highly recommend adding a href attribute to the link so it's accessible and clickable for keyboard users -- or even better, using a <button> element (which could be styled as a link if desired) to avoid other accessibility issues with using links as buttons.

dleopold commented 1 year ago

This is exactly what I was looking for. I appreciate the help. Thank you.