Robert Hawlik
Robert Hawlik

Reputation: 472

Update shiny UI only when tab is selected

I have a Shiny dashboard with multiple tabs. In one of the tabs, a slow database query fills the choices for a dropdown menu. I want the slow database query to execute only when the relevant tab is selected.

In the following ReprEx, the slowDatabaseQuery is executed at launch and blocks the R process.

library(shiny)

ui <- fluidPage(
  tabsetPanel(
    tabPanel(
      "panel1", 
      "Panel 1 content"
    ),
    tabPanel(
      "panel2", 
      "Panel 2 content",
      selectizeInput(
        "selected", 
        label = "Selector", 
        choices = NULL
      ),
      verbatimTextOutput("text")
    )
  )
)

server <- function(input, output, session) {
  slowDatabaseQuery <- reactive({
    Sys.sleep(5)
    return(c("C", "D"))
  })
  
  observe(
    updateSelectizeInput(
      session, 
      "selected", 
      choices = slowDatabaseQuery(), 
      selected = "C", 
      server = TRUE
    )    
  )
  
  output$text <- renderText(input$selected)
}

shinyApp(ui = ui, server = server)

A partial solution would be using renderUI() instead of updateSelectizeInput(). However, I would like to use the server = TRUE argument which is only available in updateSelectizeInput() and do not like that it would take the UI element a long time to appear.

Upvotes: 2

Views: 1622

Answers (1)

ismirsehregal
ismirsehregal

Reputation: 33397

We can provide your tabsetPanel with an id and observe the selections via observeEvent.

There are two different options in the code below.

  1. The DB query is done each time tab2 is selected.
  2. The DB query is done the first time tab2 is selected in the current shiny-session (commented out).

library(shiny)

ui <- fluidPage(
  tabsetPanel(
    id = "tabsetPanelID",
    tabPanel(
      "panel1", 
      "Panel 1 content"
    ),
    tabPanel(
      "panel2", 
      "Panel 2 content",
      selectizeInput(
        "selected", 
        label = "Selector", 
        choices = NULL
      ),
      verbatimTextOutput("text")
    )
  )
)

server <- function(input, output, session) {
  
  slowDatabaseQuery <- reactive({
    Sys.sleep(5)
    return(c("C", "D"))
  })
  
  observeEvent(input$tabsetPanelID,{
    if(input$tabsetPanelID == "panel2"){
      updateSelectizeInput(
        session,
        "selected",
        choices = slowDatabaseQuery(),
        selected = "C",
        server = TRUE
      )
    }
  })
  
  # observeEvent(input$tabsetPanelID == "panel2", {
  #     updateSelectizeInput(
  #       session,
  #       "selected",
  #       choices = slowDatabaseQuery(),
  #       selected = "C",
  #       server = TRUE
  #     )
  # }, once = TRUE) # should the query be done only once or each time the tab is selected?
  
  output$text <- renderText(input$selected)
}

shinyApp(ui = ui, server = server)

Upvotes: 2

Related Questions