3
votes

I'm designing a Shiny app to analyse survey results, and I want users to be able to select a question either from a selectInput dropdown ("Jump to selection") or by clicking actionButtons ("Previous", "Next"). These articles were a helpful starting point:

https://shiny.rstudio.com/reference/shiny/1.0.4/reactiveVal.html

https://shiny.rstudio.com/articles/action-buttons.html

My problem is that selectInput clashes with the results of the actionButtons, since both are controlling the same object. How do I get them to work together? I don't want to use isolate() with selectInput and make users click an additional button; I would like the selection to change as soon as they select it. Thanks!

library(shiny)

ui <- fluidPage(

   mainPanel(

     actionButton("previous_q", 
                  "Previous"), 
     actionButton("next_q", 
                  "Next"), 
     selectInput("jump", 
                 "Jump to Question", 
                 choices = 1:10), 
     textOutput("selected")

   )
)

server <- function(input, output) {

  # Select based on "Previous" and "Next" buttons -------

  selected <- reactiveVal(1)

  observeEvent(input$previous_q, {

    newSelection <- selected() - 1
    selected(newSelection)

  })

  observeEvent(input$next_q, {

    newSelection <- selected() + 1
    selected(newSelection)

  })

  # Jump to selection (COMMENTED OUT SO APP DOESN'T CRASH) ----------------

  #observeEvent(input$jump, {

    #newSelection <- input$jump
    #selected(newSelection)

  #})

  # Display selected

  output$selected <- renderText({ 
    paste(selected())                     
  })
}

shinyApp(ui = ui, server = server)
2

2 Answers

1
votes

The problem is that input$jump is a character string, not a number. Do:

  observeEvent(input$jump, {

    newSelection <- as.integer(input$jump)
    selected(newSelection)

  })
1
votes

Welcome to SO!

@StéphaneLaurent was a little faster - I'll post my solution anyway: as he already mentions you'll need as.integer(input$jump)

Furthermore you don't need the reactiveVal() "selected". This also takes care about limiting your choices:

library(shiny)

selectInputChoices = 1:10

ui <- fluidPage(mainPanel(
  actionButton("previous_q",
               "Previous"),
  actionButton("next_q",
               "Next"),
  selectInput(
    "jump",
    "Jump to Question",
    choices = selectInputChoices,
    selected = 1
  ),
  textOutput("selected")
))

server <- function(input, output, session) {
  # Select based on "Previous" and "Next" buttons -------
  observeEvent(input$previous_q, {
    req(input$jump)
    if (as.integer(input$jump) > min(selectInputChoices)) {
      newSelection <- as.integer(input$jump) - 1
      updateSelectInput(session, inputId = "jump", selected = newSelection)
    }
  })

  observeEvent(input$next_q, {
    req(input$jump)
    if (as.integer(input$jump) < max(selectInputChoices)) {
      newSelection <- as.integer(input$jump) + 1
      updateSelectInput(session, inputId = "jump", selected = newSelection)
    }
  })

  # Display selected
  output$selected <- renderText({
    req(input$jump)
    paste(input$jump)
  })
}

shinyApp(ui = ui, server = server)