1
votes

I need to generate choices for selectInput on the server side (they will change based on the changes in the database). Is there any other option than rendering the whole UI element on the server side, as in this example?

server <- function(input, output, session) {
  data("mtcars")
  output$select_cars = renderUI({
    selectInput("cyl",
                label = "Select cylinder",
                choices = mtcars %>% distinct(cyl) %>% pull %>% append("All", after = 0))
  })
}

ui = fluidPage(
  uiOutput("select_cars")
)

shinyApp(ui, server)

Something akin of creating reactive values on the server side and sending them to UI to render? If so, what is more advisable practice (or what are the pros and cons)?

1
Another option that comes to my mind is to use updateSelectInput on the start of the app. Thoughts?ayasugihada
Good summary of available options at shiny.rstudio.com/articles/dynamic-ui.html, but here indeed, and whenever it does the trick, update*Input() is preferable. It gives code that is clearer and easier to reason aboutAurèle
do you have some reproducible example with update*Input()? I tried using code from link but it does not workayasugihada
example("updateSelectInput", package = "shiny") could do, and reading help(updateSelectInput), also see my answer for another example (and for achieving "select all" in a nicer way)Aurèle

1 Answers

2
votes

Example of using updateSelectInput:

library(shiny)

ui <-  fluidPage(
  selectInput("column", "Select column", choices = names(mtcars)),
  selectInput("value", "", choices = NULL, multiple = TRUE),
  verbatimTextOutput("selected")
)

server <- function(input, output, session) {
  observeEvent(input$column, {
    updateSelectInput(session, "value", paste("Select", input$column, "value(s)"),
                      choices = sort(unique(mtcars[[input$column]])))
  })

  output$selected <- renderText({
    paste0(input$column, ": ", paste(input$value, collapse = ", "))
  })
}

shinyApp(ui, server)

Also, not OP's question, but we can see they're trying to achieve a "select all" option, I would suggest shinyWidgets::pickerInput() that has (a nice implementation of) this feature out of the box:

library(shiny)
library(shinyWidgets)

ui <-  fluidPage(
  selectInput("column", "Select column", choices = names(mtcars)),
  pickerInput("value", "", choices = NULL, multiple = TRUE, 
              options = list(`actions-box` = TRUE)),
  verbatimTextOutput("selected")
)

server <- function(input, output, session) {
  observeEvent(input$column, {
    updatePickerInput(session, "value", paste("Select", input$column, "value(s)"),
                      choices = sort(unique(mtcars[[input$column]])))
  })

  output$selected <- renderText({
    paste0(input$column, ": ", paste(input$value, collapse = ", "))
  })
}

shinyApp(ui, server)

Example that more closely mimicks OP:

ui <-  fluidPage(
  pickerInput("cyl", "", choices = NULL, multiple = TRUE, 
              options = list(`actions-box` = TRUE))
)

server <- function(input, output, session) {
  observe({
    updatePickerInput(session, "cyl", "Select cylinder", 
                      choices = sort(unique(mtcars$cyl)))
  })
}

shinyApp(ui, server)

which can even be simplified further if reactivity is not needed to update the input:

server <- function(input, output, session) {
  updatePickerInput(session, "cyl", "Select cylinder", 
                    choices = sort(unique(mtcars$cyl)))
}