rshinyreactiveselectinput

Updating selectInput in shiny app based on user selection


I have a simple shiny app with 2 select input :

shinyApp(
  ui = fluidPage(
    selectInput("Params1", "Parameter 1",choices=c('Significant wave height [m]' = 'Significant wave height',
                                                   'Peak period [s]' = 'Peak period', 
                                                   'Wind speed at 10m [m/s]' = 'Wind speed at 10m', 
                                                   'Surface current speed [m/s]' = 'Surface current speed'),selected = 'Significant wave height')
    ,selectInput("Params2", "Parameter 2", choices=c('Significant wave height [m]' = 'Significant wave height',
                                                     'Peak period [s]' = 'Peak period', 
                                                     'Wind speed at 10m [m/s]' = 'Wind speed at 10m', 
                                                     'Surface current speed [m/s]' = 'Surface current speed'),selected = 'Peak period')
  ),
  server = function(input, output,session) {
    observeEvent(input$Params1, {
      available_choices <- setdiff(c('Significant wave height [m]', 'Peak period [s]', 'Wind speed at 10m [m/s]', 'Surface current speed [m/s]'), input$Params1)
      updateSelectInput(session, "Params2", choices = available_choices, selected = input$Params2)
    })
    
    observeEvent(input$Params2, {
      available_choices <- setdiff(c('Significant wave height [m]', 'Peak period [s]', 'Wind speed at 10m [m/s]', 'Surface current speed [m/s]'), input$Params2)
      updateSelectInput(session, "Params1", choices = available_choices, selected = input$Params1)
    })
  }
)

I'm expecting upon app initiation, both select inputs appears with the selected choice, but they are not ! Am I missing something here ?!!


Solution

  • You initialize both selectInput with choices which are named, e.g. 'Peak period [s]' = 'Peak period'. From ?selectInput:

    choices: List of values to select from. If elements of the list are named, then that name — rather than the value — is displayed to the user. ...

    Now when the app is started, both of your observeEvent are firing, this is because they have ignoreInit = FALSE by default, from ?observeEvent:

    ignoreInit: If TRUE, then, when this observeEvent is first created/initialized, ignore the handlerExpr (the second argument), whether it is otherwise supposed to run or not. The default is FALSE. See Details.

    In these observeEvent you update both selectInput with e.g. input$Params2, but input$Params2 is the displayed value and hence can't match the available choices, that's why it comes to an empty field, the value which shall be set as selected is not among the available choices. However, once one ran through both observeEvent it will work because then you have updated the choices and the updated versions do not have names and carry directly the unit signs.

    Below you find a working version of your code, I just used a list instead of a vector and so the structure keeps preserved.

    library(shiny)
    
    chc <- list('Significant wave height [m]' = 'Significant wave height',
                'Peak period [s]' = 'Peak period',
                'Wind speed at 10m [m/s]' = 'Wind speed at 10m',
                'Surface current speed [m/s]' = 'Surface current speed')
    
    ui <- fluidPage(
      selectInput(
        "Params1",
        "Parameter 1",
        choices = chc,
        selected = 'Significant wave height'
      )
      ,
      selectInput(
        "Params2",
        "Parameter 2",
        choices = chc,
        selected = 'Peak period'
      )
    )
    
    server <- function(input, output, session) {
      observeEvent(input$Params1, {
        available_choices <- setdiff(chc, input$Params1)
        updateSelectInput(session,
                          "Params2",
                          choices = available_choices,
                          selected = input$Params2)
      })
      
      observeEvent(input$Params2, {
        available_choices <- setdiff(chc, input$Params2)
        updateSelectInput(session,
                          "Params1",
                          choices = available_choices,
                          selected = input$Params1)
      })
    }
    
    shinyApp(ui, server)