Search code examples
rshinyshinydashboardshiny-servershiny-reactivity

How to populate input options for shiny using information from server


I'm using a filter on a shiny app to filter a dataframe. At the moment, I have to input the possible values into the ui manually. Is there a way to read the unique values from the server dataframe and populate the input options using that list? I know it is possible to do this by making the table global, but I'm trying to avoid doing this.

Example code:

ui <- fluidPage(
  sidebarPanel(
    selectInput(inputId = 'col1Input',
                label ='col1',
                choices = c(1,2,3))),
  mainPanel(
    DT::dataTableOutput("table")))
server <- function(input,output){
  df <- data.frame('col1' = c(1,2,3), 'col2' = c(1,2,3))
  output$table <- DT::renderDataTable(dplyr::filter(df, col1 == input$col1Input))
}

shinyApp(ui = ui, server = server)

Thanks!


Solution

  • You could use renderUI to build the UI from the server. Then you could simply use one of the columns from the dataframe you have in the server to build your select input?

    See here for how to use renderUI.

    ui <- fluidPage(
      uiOutput("sidebarOutput"),
      uiOutput("mainPanel")
    )
    
    server <- function(input,output){
      df <- data.frame('col1' = c(1,2,3), 'col2' = c(1,2,3))
      output$sidebarOutput <- renderUI({
        sidebarPanel(
          selectInput(inputId = 'col1Input',
                      label =colnames(df[1]),
                      choices = df[[1]]))
      })
    
      output$mainPanel <- renderUI({
          output$table <- DT::renderDataTable({
              validate(
                need(input$col1Input != "", "No column selected")
              )
              dplyr::filter(df, col1 == input$col1Input)
            })
    
          mainPanel(
            DT::dataTableOutput("table")
          )
      })
    }
    
    shinyApp(ui = ui, server = server)
    

    Edit: You might also want to filter on a specific column that you select. You can do this like so:

    ui <- fluidPage(
      uiOutput("sidebarOutput"),
      uiOutput("mainPanel")
    )
    
    server <- function(input,output){
      df <- data.frame('col1' = c(1,2,3), 'col2' = c(4,5,6))
      output$sidebarOutput <- renderUI({
        sidebarPanel(
          selectInput(inputId = 'filtercolumn',
                      label = "Select a column to filter on",
                      choices = colnames(df)),
    
          renderUI({selectInput(inputId = 'valuetofilter',
                      label = paste0("filtering on column: ", colnames(df[input$filtercolumn])),
                      choices = df[[input$filtercolumn]])})
          )
      })
    
      output$mainPanel <- renderUI({
          output$table <- DT::renderDataTable({
              validate({
                need(input$filtercolumn != "", "No column selected")
                need(input$valuetofilter != "", "No value selected")
              })
    
              dplyr::filter(df,(!!as.name(input$filtercolumn)) == !!input$valuetofilter) #note the unquoting
            })
    
          mainPanel(
            DT::dataTableOutput("table")
          )
      })
    }
    
    shinyApp(ui = ui, server = server)
    

    With thanks to this answer