In Shiny, using updateSelectInput()
to achieve conditional filters (where the selectable choices of filter B depend on filter A) is the accepted solution to many questions (like here). However, when implementing it I often run into output objects loading twice, which is not visible on small datasets but is on real larger datasets.
I have produced a minimal example on the iris
dataset below with Sys.sleep()
representing a time consuming operation to show the double load.
What is the best way to prevent this from happening? I feel like a good req()
somewhere should do the trick but I can't find how and where.
library(shiny)
library(dplyr)
ui <- fluidPage(
selectInput("species", "Species", choices=levels(iris$Species)),
selectInput("petal_width", "Petal Width", ""),
tableOutput("iris_table")
)
server <- function(session, input, output) {
output$iris_table <- renderTable({
Sys.sleep(2) # to show the double loading time
iris %>%
filter(Species == input$species,
Petal.Width == input$petal_width)
})
petal_width_options <- reactive({
iris$Petal.Width[iris$Species == input$species]
})
observe({
updateSelectInput(session, "petal_width", choices = petal_width_options())
})
}
shinyApp(ui, server)
EDIT:
To be more specific: if you run the app and change the value of the top (Species) selector, e.g. to versicolor, the possible bottom selector (Petal Width) choices change accordingly which is what I want.
You can also see that the output table will load (render is maybe a beter term) twice. It does that, I assume, because of the execution order which first updates the species selector, than the table once (in this case temporarily resulting in an empty table) and the bottom selector once at about the same time and then the table again adjusting to the new bottom selector value. I want the table to only render once when both selector values are done updating.