1

I am currently building a Shiny app where I'd allow a user to click on a row in a reactable and show a modalDialog with more info based on that row. I followed this post (How to trigger a modalBox with observeEvent from a cell rendered button in a reactable?) to get the onclick JavaScript function.

However, when I click on the same row using this logic, nothing happens. I have to click on another row before I click back to that same row. I believe it's because input$foo does not change its value if the same row is being clicked.

I've tried setting input$foo to a different value when the modalDialog opens, but that has not been working either. Does anyone know how to work around this or reset that input$foo value after opening? I don't have a ton of experience in JavaScript. A basic Shiny example is shown below where the title of modalDialog displays the car name after clicking on the specific row.

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

ui <- fluidPage(
  fluidRow(
    column(12, align = 'center',reactableOutput("tbl"))
    )
)


server <- function(input, output, session) {
  
  data = reactive({
    mtcars %>% add_rownames('car')
  })
  
  output$tbl = renderReactable(
    reactable(
      data(),
      defaultPageSize = 10,
      compact = T,
      highlight = T,
      defaultColDef = colDef(headerClass = "bar-sort-header",
                             sortNALast = T, align = 'center',
                             headerVAlign = 'center',
                             vAlign = 'center',
                             minWidth = 60
      ),
      onClick = JS("function(rowInfo, colInfo) {
                              Shiny.setInputValue('foo', rowInfo.id)
                            }"),
      rowStyle = list(cursor = "pointer")
    )
  )
  
  observeEvent(input$foo, {
    print(input$foo)
    showModal(
      modalDialog(
        size = 'l',
        easyClose = T,
        title = data()$car[as.numeric(input$foo)+1],
      )
    )
  })
  
}

shinyApp(ui = ui, server = server)
Agrosel
  • 489
  • 3
  • 15
  • You could wait with accepting my answer, maybe someone has a better approach, since I also deal with this problem I'd be interested if there are other options :) – TimTeaFan Feb 23 '23 at 18:27

2 Answers2

3

I also run into this problem a lot and my approach is to set the input$foo to null after calling showModal so we can click again on the same row:

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

ui <- fluidPage(
  
  tags$head(
    tags$script(
    "Shiny.addCustomMessageHandler('update_input_foo', function(value) {
      Shiny.setInputValue('foo', null)
    });
    ")
  ),
  
  fluidRow(
    column(12, align = 'center',reactableOutput("tbl"))
  )
)


server <- function(input, output, session) {
  
  data = reactive({
    mtcars %>% add_rownames('car')
  })
  
  output$tbl = renderReactable(
    reactable(
      data(),
      defaultPageSize = 10,
      compact = T,
      highlight = T,
      defaultColDef = colDef(headerClass = "bar-sort-header",
                             sortNALast = T, align = 'center',
                             headerVAlign = 'center',
                             vAlign = 'center',
                             minWidth = 60
      ),
      onClick = JS("function(rowInfo, colInfo) {
                              Shiny.setInputValue('foo', rowInfo.id)
                            }"),
      rowStyle = list(cursor = "pointer")
    )
  )
  
  r <- reactiveVal(NULL)
  
  observeEvent(input$foo, {
    
    if (!is.null(input$foo)) {
    showModal(
      modalDialog(
        size = 'l',
        easyClose = T,
        title = data()$car[as.numeric(input$foo)+1],
      )
    )
    
    session$sendCustomMessage("update_input_foo", 1)

    }
  })

}

shinyApp(ui = ui, server = server)
TimTeaFan
  • 17,549
  • 4
  • 18
  • 39
2

I run into this problem a lot as well, here is a simpler approach with a random value sent each time when the row is clicked.

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

ui <- fluidPage(
  fluidRow(
    column(12, align = 'center',reactableOutput("tbl"))
  )
)


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

  data = reactive({
    mtcars %>% tibble::rownames_to_column('car')
  })

  output$tbl = renderReactable(
    reactable(
      data(),
      defaultPageSize = 10,
      compact = T,
      highlight = T,
      defaultColDef = colDef(headerClass = "bar-sort-header",
                             sortNALast = T, align = 'center',
                             headerVAlign = 'center',
                             vAlign = 'center',
                             minWidth = 60
      ),
      onClick = JS("function(rowInfo, colInfo) {
                              Shiny.setInputValue('foo', {id:rowInfo.id, nonce:Math.random()})
                             }"),
      rowStyle = list(cursor = "pointer")
    )
  )

  observeEvent(input$foo, {
    print(input$foo)

    id <- input$foo$id
    row_nr <- as.numeric(id)+1

    showModal(
      modalDialog(
        size = 'l',
        easyClose = T,
        title = data()$car[row_nr],
      )
    )
  })

}

shinyApp(ui = ui, server = server)
Remko Duursma
  • 2,741
  • 17
  • 24