This is a cross-post from SE.
The app below contains an actionButton
, a shinyWidgets::progressBar
and a selectInput
:
When the Start
button is clicked, a for-loop is triggered which loops through the numbers 1-10 and increments the progress bar at each iteration. I would also like to update the value of the selectInput
at each iteration but updateSelectInput does not work as expected. Instead of updating in tandem with the progress bar, the selectInput
value is only updated once the loop terminates. I don't understand why updateProgressBar
works here but updateSelectInput
doesn't?
A commenter on SE suggested that it could be due to updateProgressBar
using session$sendCustomMessage
internally whereas updateSelectInput
uses session$sendInputMessage
. The only difference I can think of between the two is their arguments:
sendCustomMessage: function (type, message)
sendInputMessage: function (inputId, message)
As per the help page for selectInputMessage:
sendInputMessage sends a message to an input on the session's client web page; if the input is present and bound on the page at the time the message is received, then the input binding object's
receiveMessage(el, message)
method will be called.
Here is the reproducible code:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
actionButton(inputId = "go", label = "Start"), #, onclick = "$('#my-modal').modal().focus();"
shinyWidgets::progressBar(id = "pb", value = 0, display_pct = TRUE),
selectInput('letters', 'choose', letters)
)
server <- function(input, output, session) {
observeEvent(input$go, {
shinyWidgets::updateProgressBar(session = session, id = "pb", value = 0) # reinitialize to 0 if you run the calculation several times
for (i in 1:10) {
updateProgressBar(session = session, id = "pb", value = 100/10*i)
updateSelectInput(session, 'letters', selected = letters[i])
Sys.sleep(.5)
}
})
}
shinyApp(ui = ui, server = server)
The help page mentions that the receiveMessage(el, message)
method of the binding object is called when the sendInputMessage
is received and I thought Sys.sleep
might be interfering with this somehow but I can't be sure. My actual app uses removeUI
and insertUI
to change some text under the progress bar at each iteration of the for-loop. These use session$sendInsertUI
and session$onFlushed
internally but the behaviour is the same as the updateSelectInput
. Below is an example that uses insertUI
and removeUI
:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
actionButton(inputId = "go", label = "Start"), #, onclick = "$('#my-modal').modal().focus();"
shinyWidgets::progressBar(id = "pb", value = 0, display_pct = TRUE),
div(id = 'placeholder')
)
server <- function(input, output, session) {
observeEvent(input$go, {
shinyWidgets::updateProgressBar(session = session, id = "pb", value = 0) # reinitialize to 0 if you run the calculation several times
for (i in 1:10) {
updateProgressBar(session = session, id = "pb", value = 100/10*i)
removeUI('#text')
insertUI('#placeholder', ui = tags$p(id = 'text', paste('iteration:', i)))
Sys.sleep(.5)
}
})
}
shinyApp(ui = ui, server = server)
I'm not sure what's going on here so any insight would be greatly appreciated.
EDIT: I know that all iterations in a for-loop run in the same scope whereas every iteration of an lapply has its own environment. But replacing the for-loop with lapply in my example does not work either.