I am working on a general error handler for a larger Shiny App. The idea is to open a specially styled modal dialog if an error occurs and thus notify the user that something went wrong. Since the app consists of several modules I think using a modal dialog in this case works best.
In general this already works fine, but when opening an error modal, any other modal can overwrite this error modal and thus the user might not even realise that an error occured. I don't want to stop the execution of the app when an error occurs, but want to notify the user and give him the chance to change his input and try again.
Is there a way to protect a modal from being overwritten by other modals?
Find a minimal example below. When choosing "success" all is great. But when choosing "error" you will only see the error modal because of the Sys.sleep() statement. Without it, it will be silently overwritten.
library(shiny)
# load example functions to
source("example-functions.R")
# define UI
ui <- fluidPage(
# application title
titlePanel("Error Handler"),
# sidebar with controls
sidebarLayout(
sidebarPanel(
radioButtons(inputId = "expected_outcome",
label = "Expected Outcome",
choices = list("Success",
"Error")),
actionButton(inputId = "btn_start",
label = "Execute Test")
),
# result message in main panel
mainPanel(
textOutput("user_message")
)
)
)
# server logic
server <- function(input, output) {
# define a symbol for reactive values
rv <- reactiveValues()
# define a reactive variable to display output in the UI and initialise it
rv$user_message <- "Hello World!"
# handler of the user message
output$user_message <- renderText({
rv$user_message
})
observeEvent(input$btn_start, {
message("Start Button was pressed")
# initialise result variable with `NULL`
result <- NULL
if (input$expected_outcome == "Success") {
# set UI text for success
rv$user_message <- "Success!"
} else {
# set UI text for error
rv$user_message <- "Error!"
# show a special error modal
showModal(
div(
id = "general-app-error",
modalDialog(
title = "An error occured.",
"This is the error explanation"
)
)
)
# wait for a second to demonstrate the effect
Sys.sleep(1)
}
# this modal should simulate that some other modal could come up and
# overwrite an error modal so the user will not realise that an error
# happened.
showModal(
modalDialog(
title = "App modal",
"This is the app modal, possibly overwriting other modals.",
size = "m"
)
)
}, ignoreInit = TRUE)
}
# Run the application
shinyApp(ui = ui, server = server)