I'm making an Rmarkdown html_document shiny app which has a selectInput.
I have made a minimal code example to reproduce the issue I have:
---
output: html_document
runtime: shiny
---
```{r echo=FALSE}
selectInput("selectYear", label = "Year", choices = c("All", 2006:2021), selected = "All")
observeEvent(input$selectYear, {
message("input$selectYear = ", input$selectYear)
throttle(
{
updateSelectInput(session, "selectYear", choices = c("All", 2006:2021), selected = input$selectYear)
},
100000
)
})
```<!-- -->
(you can remove the <!-- -->, that's only for code formatting here in SO. EDIT: To run this, I store it in a Rmd file and execute with rmarkdown::run("filename.Rmd", shiny_args = list(port = 5050, host = "0.0.0.0")))
This minimal app looks like this:

I have also build several charts (striped down in this minimal example) and wanted to trigger a change of selectYear with JavaScript (for example on the event of clicking a bar in chart). Here is a snippet to reproduce the issue:
Shiny.setInputValue('selectYear', 2015);
The issue I have is that this javascript triggers twice the observeEvent, we can see in the log:
input$selectYear = 2015
input$selectYear = 2015
I know it is not an issue in this example because it's too fast too notice, but when you have more code with data processing and many things happening in the app, this becomes noticeable and my chart flickers twice with whole seconds apart which is unacceptable.
Note that this double trigger doesnt happen if you use the html dropdown.
The reason to have the observeEvent is that if I don't have it, then dropdown doesn't update visually with the new value of 2015, the value only changes in the background but the dom doesnt change.
Therefore I have setup the observeEvent with updateSelectInput to change the display of the dropdown as well. I don't see any other solution for that, but if you have that could also solve my issue here.
TRIED AND FAILED:
debounce / throttle (as you can see in the snippet above)
sending a flag from JS to prevent double trigger:
Shiny.setInputValue('updateFromJS', true);
checkboxInput("updateFromJS", "updateFromJS", TRUE)
observeEvent(input$selectYear, {
message("input$selectYear = ", input$selectYear, " input$updateFromJS = ", input$updateFromJS)
if (input$updateFromJS == TRUE) {
message("updating...")
updateCheckboxInput(session, "updateFromJS", "updateFromJS", FALSE) ## i.e. input$updateFromJS <- FALSE
updateSelectInput(session, "selectYear", choices = c("All", 2006:2021), selected = input$selectYear)
}
})
I also wonder why does it run twice and not in an infinite loop.
And how come throttle and debounce do not work?
When you run
Shiny.setInputValue("selectYear", 2015), theninput$selectYeartakes the value2015, a number. Then theupdateSelectInputsetsinput$selectYearto the value"2015", a character string. There's no infinite loop because nothing changesinput$selectYearafter that.To see that: