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)
I want to provide an easier answer for anyone who doesn't require this to work with easyClose = TRUE, as the OP does -- in that case, this is a much easier solution than SBista's link in the comments.
This simply replaces the modal's default "dismiss" button with an action button of your own, which allows you to implement some additional action when you close the modal. This is set via the footer =
argument.
In this example, the modal contains checkboxes, which don't take effect until the modal is closed.
library(shiny)
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) {
## These values allow the actions made in the modal to be delayed until the
# modal is closed
values = reactiveValues(to_print = "", ## This is the text that will be displayed
modal_closed=F) ## This prevents the values$to_print output from
# updating until the modal is closed
## Open the modal when button clicked
observeEvent(input$display_modal,{
values$modal_closed <- F
showModal(modalDialog(
checkboxGroupInput("checkboxes",label = "Select letters",
choices = LETTERS[1:7]),
## This footer replaces the default "Dismiss" button,
# which is 'footer = modalButton("Dismiss")'
footer = actionButton("dismiss_modal",label = "Dismiss")
))
})
## This event is triggered by the actionButton inside the modalDialog
# It closes the modal, and by setting values$modal_closed <- T, it
# triggers values$to_print to update.
observeEvent(input$dismiss_modal,{
values$modal_closed <- T
removeModal()
})
## values$to_print is only updated once the modal is closed.
observe({
if(values$modal_closed){
values$to_print <- paste(input$checkboxes)
}
})
## Forward the values$to_print to the UI
output$checked_letters = renderText({values$to_print})
}
)
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})
}
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With