Regarding the best practice:
Usually validate is directly placed in render* functions - this also avoids the unwanted eventReactive output:
library(shiny)
library(shinyalert)
ui <- fluidPage(
useShinyalert(),
titlePanel("Validation/actionButton/eventReactive replex"),
sidebarLayout(
sidebarPanel(
p(
"Clicking the button without changing the value results in an error messages and suppresses the modal popup. Change the value to get the popup and see the object returned by shinyalert."
)
),
mainPanel(
numericInput("test",
h4("Test input"),
value = 2700,
min = 0),
verbatimTextOutput("test_box"),
actionButton("go", "Execute")
)
)
)
server <- function(input, output) {
observeEvent(input$go, {
if(input$test != 2700){
shinyalert(title = "The value you entered is:",
text = input$test,
type = "success")
}
})
output$test_box <- renderText({
validate(need(input$test != 2700, "This value can't be 2700"))
})
}
shinyApp(ui = ui, server = server)
Personally I think, opening a modal after the user enters an unsuitable value is a little too much - but it depends on the usecase I guess.
You might want to check out RStudio's shinyvalidate package, which marks the invalid inputs red to notify the user:
Here is an alternative implementation using shinyvalidate:
library(shiny)
library(shinyvalidate)
ui <- fluidPage(
titlePanel("Validation/actionButton/eventReactive replex"),
sidebarLayout(
sidebarPanel(),
mainPanel(
numericInput("test",
h4("Test input"),
value = 2700,
min = 0),
actionButton("go", "Execute")
)
)
)
server <- function(input, output) {
iv <- InputValidator$new()
iv$add_rule("test", sv_integer())
iv$add_rule("test", sv_not_equal(2700))
iv$enable()
observeEvent(input$go, {
req(iv$is_valid())
showNotification("This triggered something useful.", type = "message")
})
}
shinyApp(ui = ui, server = server)