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.