3

Take this example from the reactable documentation (interactive Shiny example provided at link):

data <- cbind(
  MASS::Cars93[1:5, c("Manufacturer", "Model", "Type", "Price")],
  details = NA
)

reactable(
  data,
  columns = list(
    # Render a "show details" button in the last column of the table.
    # This button won't do anything by itself, but will trigger the custom
    # click action on the column.
    details = colDef(
      name = "",
      sortable = FALSE,
      cell = function() htmltools::tags$button("Show details")
    )
  ),
  onClick = JS("function(rowInfo, colInfo) {
    // Only handle click events on the 'details' column
    if (colInfo.id !== 'details') {
      return
    }

    // Display an alert dialog with details for the row
    window.alert('Details for row ' + rowInfo.index + ':\\n' + JSON.stringify(rowInfo.row, null, 2))

    // Send the click event to Shiny, which will be available in input$show_details
    // Note that the row index starts at 0 in JavaScript, so we add 1
    if (window.Shiny) {
      Shiny.setInputValue('show_details', { index: rowInfo.index + 1 }, { priority: 'event' })
    }
  }")
)

I want to include 2 buttons per details column cell, which I can do by changing the cell definition to:

                             cell = function() {
                              a <- htmltools::tags$button("Approve")
                              b <- htmltools::tags$button("Decline")
                              return(list(a,b))
                             }

But then how to differentiate between the Approve/Decline button within the JS() onClick() function? Is there another parameter I can pass that will give me this ability? I console.log'd both rowInfo and colInfo and could not find anything that seemed helpful to identify the two buttons. I'd like to have it so that I can return both:

Shiny.setInputValue('approve_button_click', ...)

and

Shiny.setInputValue('decline_button_click',...)

from the JS side so I can handle them separately in R. Any help is appreciated!

Kyle Weise
  • 869
  • 1
  • 8
  • 29

1 Answers1

3

If you want to get just the row index you can do:

library(htmltools)

details = colDef(
  name = "",
  sortable = FALSE,
  cell = function(value, rowIndex, colName){
    as.character(tags$div(
      tags$button("Approve", onclick=sprintf('alert("approve - %d")', rowIndex)),
      tags$button("Decline", onclick=sprintf('alert("decline - %d")', rowIndex))
    ))
  },
  html = TRUE
)

In Shiny:

reactable(
  data,
  columns = list(
    details = colDef(
      name = "",
      sortable = FALSE,
      cell = function(value, rowIndex, colName){
        as.character(tags$div(
          tags$button(
            "Approve", 
            onclick = 
              sprintf(
                'Shiny.setInputValue("approve", %d, {priority: "event"})', 
                rowIndex
              )
          ),
          tags$button(
            "Decline", 
            onclick = 
              sprintf(
                'Shiny.setInputValue("decline", %d, {priority: "event"})', 
                rowIndex
              )
          )
        ))
      },
      html = TRUE
    )
  )
)
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • This is perfect! Thank you @Stéphane! I hadn't of thought of using the onClick function of the `tags$button`. – Kyle Weise Aug 24 '21 at 12:54
  • Hi @Stephane. I would be grateful if you could have a look at [this](https://stackoverflow.com/q/73997808/8689932)] question and perhaps give some hints – Lefkios Paikousis Oct 09 '22 at 20:16