2

Following on from this post, I wonder why showModal() inside of observeEvent() does not get triggered when i click on the cell rendered button? I give the button the fixed ID 'character' on which the observeEvent() should listen and then open the modal box. But it doesnt.

Where is the difference if i place a button in the ShinyApp UI, where the observeEvent() would react to the inputid, or if I place it in a reactable?

library(shiny)
library(reactable)
library(tidyverse)

data = dplyr::starwars %>%
  select(name, height, mass, sex, species, homeworld)

ui = fluidPage(
  
  column(width = 6, style = "margin-top: 50px;",
  reactableOutput("table"))
  
)

server = function(input, output, session){

  
  output$table = renderReactable({
    reactable(data = data,
              height = 600,
              defaultPageSize = 20,
              columns = list(
                name = colDef(
                  cell = function(value){
                    div(htmltools::tags$button(value, class = "action-button", id = "character"))
                  })))})
  
  observeEvent(input$character, {
  showModal(modalDialog(title = "Test"))
  })
}

shinyApp(ui, server)
werN
  • 109
  • 7

1 Answers1

1

The reactable package provides many examples how you can work with it including a custom action in each row. The sample has a column "details" and it shows elements looking like button. With the Javascript function there it identifies clicks on the details column and acts accordingly.

Add this as additional argument to the reactable call in renderReactable.

reactable(
  data = data,
  height = 600,
  defaultPageSize = 20,
  ...
  onClick = JS("function(rowInfo, colInfo) {
    // Only handle click events on the 'details' column
    if (colInfo.id !== 'details') {
      return
    }

    // Send the click event to Shiny
    if (window.Shiny) {
      Shiny.setInputValue('foo', 'bar')
    }
  }")
)

Shiny.setInputValue("foo", "bar") will cause the server’s input$foo to be set to "bar". That leads to a Shiny event which you can catch in the server e,g, with an observer. See this tutorial about Javascript in R for details.

Please note: The authors of reactable do not recommend using this because "custom click actions are currently not accessible to keyboard users" (quote from the manual 2021-10-16). If accessibility or other reasons for keyboard use are not relevant for you, you can use this solution.

Note about the "class"-solution: I would not advise to use class = "action-button" because I believe it to be a fragile construct. That is no proper way to create an input binding and I am surprised it works at all.

The only package that I know which officially supports buttons in table rows is DataTables with the Buttons extension.

Jan
  • 4,974
  • 3
  • 26
  • 43
  • I know these examples from the reactabel package but none of these goes into the direction where I was pointing to in my post. I need to trigger a modalbox in which I can write R Code, not JS Code. And what do you mean by "shows elements looking like button"? These are buttons, aren't they? – werN Oct 16 '21 at 21:28
  • I do not understand. With `Shiny.setInputValue` you create events that you can handle in the R server function with an observer and write whatever R code you need to write. What is missing? – Jan Oct 17 '21 at 07:19
  • Regarding the question about the ui elements that look like buttons: actually, they are fake. The click does not respond to a click on the button but to clicking the whole table cell. You can try it. The demo responds to your clicks even when you click a few pixels beside the button. – Jan Oct 17 '21 at 07:22
  • Your right that with `Shiny.setInputValue` in the `onClick` parameter i can handel various events in R server function, and this works for me very well, thanks! Nevertheless i wonder why `cell = function(value){div(tags$button(value, onclick = "Shiny.setInputValue('foo', 'bar', {priority: 'event'})"))}` wont work as it basically seems to be exactly the same. – werN Oct 17 '21 at 09:18
  • The difference is the specification of both functions. The reactable knows the `onClick` argument. It is part if it's specification and it provides the necessary logic to run whatever Javascript you put there. The `tags$button` button on the other hand is not aware of `onClick`. It takes every named argument and coerces it into an HTML attribute. But, of course, that won't do you no good. – Jan Oct 17 '21 at 09:47
  • When i place the "so called" button in the Shiny Ui with `onclick` argument like so `htmltools::tags$button("button", "Label", onclick = "Shiny.setInputValue('foo', 'bar', {priority: 'event'})")` it works. But let's leave it at that, it must somehow be prevented from reactable when i write it in the cell argument like in my previous post. – werN Oct 18 '21 at 06:43