I am coding a Shiny App, which generates some plots upon pressing a button. The calculation starts when the user presses the butten, and I want to update the label of the button once it is pressed to show that the calculation is currently happening. After the calculation is finished, it should revert back to the "default" state. I thought this would be easy to do with updateActionButton
, but somehow I cant get it to work. Here is a small reproducible example.
if (interactive()) {
ui <- fluidPage(
actionButton("update", "Do calculation"),
)
server <- function(input, output, session) {
observeEvent(input$update, {
# Change the button label
updateActionButton(session, "update", label = "Running calculation")
# This is a random calculation which takes a few seconds as a placeholder.
result <- 0
for (i in 1:5000000) {
result <- result + sqrt(i)
}
updateActionButton(session, "update", label = "finished calculation")
})
}
shinyApp(ui, server)
}
It seems like it simply skips the first updateActionButton
call…
Any insights into what I am doing wrong are much appreciated!
Cheers!
2
Answers
With the help of Mwavu, I managed to accomplish what I was trying. Although to be honest, I dont really understand why it works and would greatly appreciate if somebody could explain to me why it works.
Specifically, I do not understand why it is necessary to include the
textOutput("renderStatus")
and theoutput$renderStatus
. I thought it should be enough to have this code blockto trigger the default state of the button.
What is happening?
From
?updateActionButton
:This means that when you click on the button, the updates will only be sent once the
for
loop is done.Since you’re trying to update the label of the button twice, only the last update is sent to the client.
There are several solutions, I’m going to highlight the 2 easiest ones:
Solution 1
Set the
onclick
attribute of the button.This way, you avoid requiring communication from the server for the UI to update. All the server needs to do is alert the client once it is done with the calculations.
Solution 2
Use
{shinyFeedback}
.This way, you’ll avoid writing ad-hoc inline js like in Solution 1 above. You’ll also get a nice spinner on the button.