rshinyreactivepickerinput

Updating pickerInput reactively with observeEvent


I am trying to update two pickerInput's via an observeEvent, based on the dataframe it produces. The two inputs should reflect one another; in other words, only show possible options in both pickers depending on each other's selections.

However, it is throwing out an error message:

Warning: Error in $: $ operator is invalid for atomic vectors
  3: runApp
  2: print.shiny.appobj
  1: <Anonymous>

I've produced an example below. I've checked to see if data() is an atomic vector or not, and it seems to be maintained as a dataframe.


l <- NULL
l$name <- c('b','e','d','b','b','d','e')
l$age <- c(20,20,21,21,20,22,22)
l <- as.data.frame(l)
l$name <- as.character(l$name)
l$age <- as.numeric(l$age)
library(shiny)

server <- shinyServer(function(input,output, session){
  
  data <- reactive({
    if(length(input$name) > 0 & length(input$age) > 0){
      l %>% filter(age %in% input$age, 
                   name %in% input$name)
    }else if (length(input$name) > 0 & length(input$age) == 0){
      l %>% filter(name %in% input$name)
    }else if (length(input$name) == 0 & length(input$age) > 0){
      l %>% filter(age %in% input$age)
    }
    else{
      l
    }
  })
  
  observeEvent(list(
    input$name,
    input$age
  ),
  ignoreInit = TRUE,
  {
    updatePickerInput("age","Choose an age",
                      choices = c(unique(data()$age)))
    updatePickerInput("name","Choose a name",
                      choices = c(unique(data()$name)))
    print(str(data()))
    print(is.data.frame(data()))
    print(is.atomic(data()))
    print(is.atomic(data()$name))
    print("x")
  })
  
  output$table1 <- renderTable({
    data()
  })
  }
  )

ui <-shinyUI(fluidPage(
  pickerInput("name","Choose a name", choices = c(unique(l$name)), 
              options = list(`actions-box` = TRUE),
              multiple = T),
  pickerInput("age","Choose an age", choices = c(unique(l$age)), 
              options = list(`actions-box` = TRUE),
              multiple = T),
  tableOutput("table1")
))

shinyApp(ui,server)

Note: adding the below removes the error, but does not update the pickers:

updatePickerInput(inputId = "age", label ="Choose an age",
                      choices = c(unique(data()$age)), 
                      options = list(`actions-box` = TRUE))
    updatePickerInput(inputId = "name",label = "Choose a name", choices = c(unique(data()$name)), 
                      options = list(`actions-box` = TRUE))`

Solution

  • First, your second code is correct, i.e. you have to name the inputId = argument. In your first code you are passing the input id to the session= argument which is the first argument of updatePickerInput. And this results in the error you get.

    Second, the issue is that you are running in circles. Your picker inputs get updated. But the update itself triggers the next round of updates as selected= defaults to NULL and hence this update will restore the original choices.

    Instead, one option to fix that would be to set the selected= argument when updating and by using a separate observeEvent for each picker:

    observeEvent(
      input$age,
      ignoreInit = TRUE,
      {
        updatePickerInput(
          inputId = "name", choices = unique(data()$name),
          selected = input$name
        )
      }
    )
    
    observeEvent(
      input$name,
      ignoreInit = TRUE,
      {
        updatePickerInput(
          inputId = "age", choices = unique(data()$age),
          selected = input$age
        )
      }
    )
    

    enter image description here