Simon
Simon

Reputation: 1111

Make renderUI an input for observeEvent

As the title suggests, I wish to make a dynamically created UI object (using renderUI) which can be further manipulated later in the Shiny App.

In the below reprex, I have a toy application which allows a user to filter the iris dataset based on the sepal width. Depending on the range the user selects, I then generate a checkbox list of all the unique species within that sepal width range.

My question is: how can I make the app tell me which species' checkbox has been selected once the user has filtered the table? For example, at the default app settings when the sepal width range is between 1 and 2, only one species is satisfies the filter requirement (versicolor). When a user checks the versicolor box, I would like the app to update to tell me that versicolor has been selected.

Similarly, when the sepal width range is greater (and more species are then included in the dynamically generated checkbox list) I would like the UI to update again to tell me which species was selected (either 1, 2 or all 3 species).

The basic workflow in my head is:

(1) User filters Dataset (2) Displayed Table Updates Based on Filter (3) App Generates Checkbox List of Unique Species (4) User Clicks on Species, Species Name is Presented on-screen.

library(shiny)
library(DT)
library(dplyr)

ui <- basicPage(

  fluidRow(
    uiOutput("ui"),
    sliderInput("slider", "Sepal Width", min = 0, max=20, value=c(1:2)),
    tableOutput("data")

  ),

)



server <- function(input, output){

  data("iris")

  filtered<-reactive({

    iris %>% filter(`Sepal.Width` %in% input$slider[1]:input$slider[2])


  })

  output$data<-renderTable({

    filtered()

  })

  output$ui<-renderUI({

    species<-filtered() 
    checkboxGroupInput(inputId = 'occurence_checkboxes', label = 'Species', choices = unique(species$Species))

  })




}

shinyApp(ui, server)

Upvotes: 2

Views: 1194

Answers (1)

thothal
thothal

Reputation: 20399

This should do the trick:

library(shiny)
library(dplyr)

ui <- basicPage(
  fluidRow(
    uiOutput("ui"),
    sliderInput("slider", "Sepal Width", min = 0, max=20, value = 1:2),
    tableOutput("data")
  )
)

server <- function(input, output){
  get_width_filter <- reactive({
     iris %>% filter(between(Sepal.Width, input$slider[1], input$slider[2]))
  })

  get_ovl_filter <- reactive({
     get_width_filter() %>%
       filter(Species %in% input$occurence_checkboxes)
  })

  output$data <- renderTable({
    get_ovl_filter()
  })

  output$ui <- renderUI({
    choices <-  get_width_filter() %>% pull(Species) %>% unique()
    checkboxGroupInput("occurence_checkboxes", 
                       "Species", 
                       choices = choices, 
                       selected = choices)
  })
}

shinyApp(ui, server)

Explanation

We need to split the filtered routine in 2 parts: 1 which applies just the width filter and one which also incorporates the species filter. You can access the dynamically created checkbox via the name which you you use in your renderUI function. The reason that we have to split the filter reactive is that otherwise the renderUI would take dependence on the checkbox itself which we want to avoid.

Update

I just read that you just wanted to return the values of the checkbox not use it to filter. But I guess that this should be clear now, just use input$occurence_checkboxes whereever you need it.

Upvotes: 2

Related Questions