Observe modal (easy) closing in Shiny

Viewed 4932

I'm looking for a way to trigger an event based upon closing of a Shiny modal when the easy-close option is TRUE (so clicking outside the modal closes it). Since there is no ID linked to a modal, I can't seem to catch this event. I tried wrapping the modal in an 'observe' event, but this only triggers the opening but not closing of the modal.

Any ideas... Thanks


example: I want to trigger an event if this modal closes by clicking outside of it, so not the dismiss button. The code below only triggers when opening...

library(shiny)
ui <- fluidPage(
  fluidRow(
    actionButton(inputId = "enterText", label = "Enter name", align = "left"),
    h1(textOutput("myOutput"))
  )
)

server <- function(input, output, session) {
  myText <- reactiveValues(input = "...")
  myModal = modalDialog(h3("Enter a string, then click outside this modal to close and display the text"),
                        textInput(inputId = "myString", label = "Enter a string: "),
                        title = "Input", easyClose = TRUE, footer = modalButton("Dismiss"))
  test = observe(myModal)

  #Open the modal when button clicked
  observeEvent(input$enterText,{
    showModal(myModal)
    })

  #Observe the modal, should fire when it CLOSES by clicking outside the modal (easy-close)
  observeEvent(test, {
    myText$input = input$myString
    print("observed")
  }, ignoreInit = T)

  output$myOutput = renderText(myText$input)

}

shinyApp(ui = ui, server = server)
2 Answers

Similar to the first answer, my approach only works with easyClose = FALSE. Instead of using an actionButton together with an observeEvent we could create a custom function modalActionButton, which is basically copy paste from actionButton and just adding data-dismiss = "modal":

I adapt the example from the first answer below:

library(shiny)

# this is basically copied from actionButton() and just "`data-dismiss` = "modal" 
# from modalButton() is added:
modalActionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {
  
  value <- restoreInput(id = inputId, default = NULL)
  tags$button(id = inputId, type = "button", style = if (!is.null(width)) 
    paste0("width: ", validateCssUnit(width), ";"), type = "button", 
    class = "btn btn-default action-button", `data-dismiss` = "modal", `data-val` = value, 
    list(shiny:::validateIcon(icon), label), ...)
  
}

shinyApp(

    ui <- fluidPage(
    fluidRow(
      ## Button to display modal:
      actionButton(inputId = "display_modal",label = "Display modal"),
      
      ## Print the choices that were made in the modal:
      h1(textOutput("checked_letters"))
    )
  ),
  
  server <- function(input, output) {
    
    values = reactiveValues(to_print = "")   ## This is the text that will be displayed

    observeEvent(input$display_modal, {
      showModal(modalDialog(
        checkboxGroupInput("checkboxes",label = "Select letters",
                           choices = LETTERS[1:7]),

        title = "This is a modal page with a 'modalActionButton' ",
        size = "l",
        easyClose = FALSE,
        # here is the modalActionButton
        footer = modalActionButton("close",
                                   "Close")
      ))
    })

    observeEvent(input$close, {
        values$to_print <- input$checkboxes
      })

    ## Forward the values$to_print to the UI
    output$checked_letters <- renderText({values$to_print})

   }
)
Related