0

I have a Shiny app in which a pickerInput() is updated based on the value selected in another pickerInput().

library("shiny")
library("shinyWidgets")

ui <- fluidPage(
  shinyjs::useShinyjs(),
  tags$h2("Update pickerInput"),
  
  fluidRow(
    column(
      width = 5, offset = 1,
      pickerInput(
        inputId = "pl",
        label = "Lower",
        choices = letters
      )
    ),
    column(
      width = 5,
      pickerInput(
        inputId = "pu",
        label = "Upper",
        choices = LETTERS
      )
    )
  ),
  
  fluidRow(
    column(
      width = 10, offset = 1,
      actionButton("b1", label = "Update 1"),
      actionButton("b2", label = "Update 2"),
      textOutput("pu_printed"),
    )
  )
  
)

server <- function(input, output, session) {
  
  observeEvent(input$b1, {
    updatePickerInput(
      session = session, inputId = "pu",
      selected = LETTERS[letters == input$pl]
    )
    shinyjs::click("b2")
  })
  
  pur <- eventReactive(input$b2, {
    print(input$pu)
    input$pu
  })
  
  output$pu_printed <- renderText({
    paste("Selected Upper: ", pur())
  })
  
}

shinyApp(ui = ui, server = server, options = list(launch.browser = TRUE))

enter image description here

I expect that upon selecting a value with the "Lower" input and clicking the "Update 1" button, the following should happen:

  1. "Upper" input will automatically update based on the value in the "Lower" input
  2. The (new) value in the "Upper" input (from step 1) will print to the console
  3. The (new) value in the "Upper" input (from step 1) will be rendered as text under the buttons.

However, only expectation 1 actually occurs (the "Upper" input is updated). However, the console printout and text render remain set to the previous value ("A" in the case below).

enter image description here

Changing the "Lower" input and clicking "Update 1" again shows that the rendered text has updated to the first selection from "Lower" (in this case, "M"). Essentially, the rendered text is always one selection behind.

enter image description here

The same thing happens when the UI is generated dynamically. I have not reproduced the screenshots because the results are the same, but here is the code.

library("shiny")
library("shinyWidgets")

ui <- fluidPage(
  shinyjs::useShinyjs(),
  tags$h2("Update pickerInput"),
  
  uiOutput("o1")
  
)

server <- function(input, output, session) {
  
  output$o1 <- renderUI({
    tagList(fluidRow(
      column(
        width = 5, offset = 1,
        pickerInput(
          inputId = "pl",
          label = "Lower",
          choices = letters
        )
      ),
      column(
        width = 5,
        pickerInput(
          inputId = "pu",
          label = "Upper",
          choices = LETTERS
        )
      )
    ),
    fluidRow(
      column(
        width = 10, offset = 1,
        actionButton("b1", label = "Update 1"),
        actionButton("b2", label = "Update 2"),
        textOutput("pu_printed"),
      )
    ))
  })
  
  observeEvent(input$b1, {
    updatePickerInput(
      session = session, inputId = "pu",
      selected = LETTERS[letters == input$pl]
    )
    shinyjs::click("b2")
  })
  
  pur <- eventReactive(input$b2, {
    print(input$pu)
    input$pu
  })
  
  output$pu_printed <- renderText({
    paste("Selected Upper: ", pur())
  })
  
}

shinyApp(ui = ui, server = server, options = list(launch.browser = TRUE))

I know that the shinyjs::click("b2") is firing correctly because the print() statement is output to the console, however the value input$pu appears to always be one selection behind. What do I need to change so that the updated value of input$pu is available when shinyjs::click("b2") fires?

Wil
  • 3,076
  • 2
  • 12
  • 31
  • This is familiar problem. In my experience, the best way to do something like this is with dynamic inputs in your server script and `renderUI`. Those updateInput functions can be difficult to fit in to the reactive chain of events, as you are experiencing. – SmokeyShakers Mar 02 '23 at 17:26
  • In your case, 2 and 3 are working as expected. If you want it to show immediate reactivity, please change `pur <- eventReactive(..)` to `pur <- reactive(...)` – YBS Mar 02 '23 at 17:39
  • @SmokeyShakers using dynamic input has the same issue (I have added example code to the post). – Wil Mar 02 '23 at 19:39
  • I mean making ONLY your picker input that is named pu, dynamic and getting rid of the updatePickerInput entirely. Ideally you want the button firing to filter a reactive vector of choices. Then, when that vector is filtered, the input will re-render with the new choices. – SmokeyShakers Mar 02 '23 at 20:11

0 Answers0