5

In my shiny app, I have two SelectInput objects with choices that are dependent between the two (there can be multiple choices in both lists).

When I interact with widget A, there might be choices in widget B that are no longer applicable so that I'd like to update the selection and choices in widget B accordingly.

Is there a way to update choices and selections using updateSelectInput that does not trigger an event? In other words, is there a way to avoid invalidating input$widgetB?

Edit:

The example below shows my problem.

I used browser() to track the chain of reactions. If Widget B only has 'X' selected, then Widget A should only show 'A' and 'B' as options (i.e., 'C' is no longer an option). Similarly, If Widget A only has 'C' selected, then Widget B should only show 'Y' and 'Z' as options (i.e., 'X' is no longer an option). Because of the way it is set up, the reaction chain ultimately reverts all choices to the initial set. I do not think I would have this problem if there was a way for updateSelectInput to stop invalidating the related widget when choices/selections change (note below that updateSelectInput is smart enough to not invalidate the related widget if we replaced current choices/selections with the same values).

Any ideas how I could achieve the desired outcome?

library(shiny)

ui <- fluidPage(
  selectInput(
    "WidgetA",
    label = h3("Widget A"),
    choices = c("A", "B", "C"),
    selected = c("A", "B", "C"),
    multiple = TRUE
  ), 
  selectInput(
    "WidgetB",
    label = h3("Widget B"),
    choices = c("X", "Y", "Z"),
    selected = c("X", "Y", "Z"),
    multiple = TRUE
  ),
  tableOutput("table")
)

server <- function(input, output, session) {

  D <- data.frame(A = c("A","A","B","B","B","C","B","C","C","A"),
                  B = c("X","Y","Z","X","Y","Z","X","Y","Z","X"),
                  x = 1:10
                  )

  observeEvent(input$WidgetA,{
    # browser()

    B_choices <- unique(D$B[D$A %in% input$WidgetA])

    # Does not trigger update (i.e., it does not invalidate input$WidgetB) if choices AND selections remain the same
    updateSelectInput(session, "WidgetB", choices = B_choices, selected = B_choices)

    D_ <- D[D$A %in% input$WidgetA & D$B %in% input$WidgetB,]

    output$table <- renderTable(D_)
  })

  observeEvent(input$WidgetB,{
    # browser()

    A_choices <- unique(D$A[D$B %in% input$WidgetB])

    # Does not trigger update (i.e., it does not invalidate input$WidgetA) if choices AND selections remain the same
    updateSelectInput(session, "WidgetA", choices = A_choices, selected = A_choices)

    D_ <- D[D$A %in% input$WidgetA & D$B %in% input$WidgetB,]

    output$table <- renderTable(D_)
  })

}

shinyApp(ui = ui, server = server)
Hector
  • 51
  • 3
  • 4
    When asking for help, you should include a simple [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output that can be used to test and verify possible solutions. It's hard to talk about specific solutions with no code at all. – MrFlick Mar 07 '18 at 17:02
  • Note sure to understand evrything what you need (without reproductible minimal example), but it seems you look for ```isolate``` function which allows you to stop reaction, check the documentation by Rstudio [here](https://shiny.rstudio.com/articles/isolation.html) – Thomas Mar 07 '18 at 17:23
  • Thank you for the comments. I've updated the question with a specific example. – Hector Mar 07 '18 at 21:49

1 Answers1

0

You can use renderUI in the server side of things to render a selectInput which is dependent on the value from another. You then add this you your UI using the uiOutput function:

library(shiny)

ui <- fluidPage(

  selectInput(
    "widgetA",
    label = h3("Widget A"),
    choices = c(1,2,3,4)
  ),
  uiOutput("select2")
  )

server <- function(input, output) {
   output$select2 <- renderUI({
     if(input$widgetA %in% c(1,2)) {
    selectInput(
      "WidgetB",
      label = h3("Widget B"),
      choices = c("A", "B", "C")
    ) }
    else {
      selectInput(
        "WidgetB",
        label = h3("Widget B"),
        choices = c("X", "Y", "Z")
      )
    } 
  })
}
shinyApp(ui = ui, server = server)
GJPlatten
  • 168
  • 1
  • 9
  • Thank you for the answer. I've added an example to be more specific and clear on what my issue is. – Hector Mar 07 '18 at 21:50