glin / reactable

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

Clicking same button twice for custom button doesn't trigger reactivity #139

Closed aavanesy closed 3 years ago

aavanesy commented 3 years ago

Please see the example below.

When I click on the same Details button more than once it does not trigger

library(shiny)
library(reactable)

ui <-  div(
  reactableOutput('mytable'),
  hr(),
  textOutput('text'),
  hr()
)

server <- shinyServer(function(input, output, session) {

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

  output$mytable = renderReactable({
    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 })
    }
  }")
    )
  }) 

  val <- reactiveVal('')

  observeEvent(input$show_details,{
    print(input$show_details$index)
    v = input$show_details$index
    val(paste(val(),v))
  })

  output$text <- renderText({
    val()
  })

})

shinyApp(ui = ui, server = server)
aavanesy commented 3 years ago

Solved it with this solution...

    if (window.Shiny) {
       Shiny.setInputValue('show_details', { index: 0})
      Shiny.setInputValue('show_details', { index: rowInfo.index + 1 })
    }
glin commented 3 years ago

Glad you found a solution. As an alternative, Shiny also added a feature a while back to help with issues like this:

If you’re using input$foo to provide notifications that, say, a button has been clicked, you don’t want Shiny to “helpfully” suppress some of those notifications in an effort to save you work. You want to be notified for every call of Shiny.setInputValue.

As of Shiny v1.1, you can opt out of the optimizations and have Shiny notify you of every set, by passing a priority: "event" option:

Shiny.setInputValue("foo", "bar", {priority: "event"});

This will cause input$foo to notify any reactive objects that depend on it, whether its value has actually changed or not.

https://shiny.rstudio.com/articles/communicating-with-js.html

I think I'll change the example in the docs to set input values like this.