Alex W
Alex W

Reputation: 747

RShiny event listener doesn't wait for user input every time

I am working on an RShiny application that will allow a user selection after they click a button in the UI. This selection will be used later in the code, so I would like the app to wait for the user to make their selection before proceeding. In the example here, after the user clicks on the button, they are presented with 3 checkbox options. They can take as long as they want to make their selection, and the options they choose are printed to the R console. The code is run once and then stops, exactly how I would like it to behave. However, when the user clicks the button a 2nd time, the dialog immediately disappears and prints out their previous selection and the code runs once. On a third click, the dialog box waits for input again, but after a selection the code runs 3 times! (you can verify this by the R console output or the UI notifications). How can I restructure my code so that the popup dialog waits for user input every time and only runs the code once?

Here is the example app.R file:

library(shiny)

ui <- shinyUI(fluidPage(
  actionButton(inputId="myButton", label="Run code by clicking button")
))

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

  # Define the modal dialog
  buttonModal <- function(failed = FALSE) {
    
    modalDialog(
      checkboxGroupInput(inputId = "options", label = "Make a selection", choices = c("Option 1", "Option 2", "Option 3")), 
      if (failed)
        div(tags$b("something went wrong")), 
      
      footer = tagList(
        modalButton("Cancel"), 
        actionButton(inputId = "ok", label = "OK")
      )
    )
  }
  
  observeEvent(input$myButton, {
    print("clicked button")
    
    #display the dialog after user clicks button
    showModal(buttonModal())

    # Wait to run rest of code until user clicks OK
    observeEvent(input$ok, {
      print(input$options)
      removeModal()
      
      showNotification("Running code... Please wait.")
      print("Finished running.")
      print("-------------------------------------------------------")
      showNotification("Finished running.")
    })
  })
})

shinyApp(ui, server)

Upvotes: 0

Views: 615

Answers (1)

Ash
Ash

Reputation: 1513

Avoid nesting observeEvent, i.e. don't put observeEvent(input$ok, inside observeEvent(input$myButton,. Nesting them can cause weird behaviour.

Here is your code with that change made:

library(shiny)

ui <- shinyUI(fluidPage(
    actionButton(inputId="myButton", label="Run code by clicking button")
))

server <- shinyServer(function(input, output, session) {
    
    # Define the modal dialog
    buttonModal <- function(failed = FALSE) {
        
        modalDialog(
            checkboxGroupInput(inputId = "options", label = "Make a selection", choices = c("Option 1", "Option 2", "Option 3")), 
            if (failed)
                div(tags$b("something went wrong")), 
            
            footer = tagList(
                modalButton("Cancel"), 
                actionButton(inputId = "ok", label = "OK")
            )
        )
    }
    
    observeEvent(input$myButton, {
        print("clicked button")
        
        #display the dialog after user clicks button
        showModal(buttonModal())
        
    })
    
    observeEvent(input$ok, {
        print(input$options)
        removeModal()
        
        showNotification("Running code... Please wait.")
        print("Finished running.")
        print("-------------------------------------------------------")
        showNotification("Finished running.")
    })
    
})

shinyApp(ui, server)

Upvotes: 2

Related Questions