Previous User input automatically triggering modalDialogs of next round of user input

Hello, I really need help with this issue that I'm having. I've tried so many different tricks and none of them seem to work.

So the premise of a certain module in my shiny application is to run a formula with interactive modalDialogs to assist in the process. The process (WGCNA analysis) involves a lot of user input based on graphical output, so I ask for user input where appropriate, and continue on with the calculation given the new user input.
For example, here's some pseudocode below:

showModal(
  modalDialog(
    ui = user_input_1, 
      footer = tagList( actionButton(inputId = "submit_1", "Submit") )
   )
)

observeEvent(input$submit_1, {
  first_calc <- stuff_with_user_input_1
  output$plot_1 <- renderPlot( plot_using_first_calc )
  showModal(
    modalDialog(
      text = "Based on the graph below, select an outlier cutoff:",
      user_input_2,
      plotOutput("plot_1"),
      footer = tagList( actionButton(inputId = "submit_2", "Submit") )
    )
  )
  observeEvent(input$submit_2, {
    second_calc <- stuff_with_user_input_2 * first_calc
    output$plot_2 <- renderPlot( plot_using_second_calc )
    showModal(
      modalDialog(
        text = "Based on the graph below, choose a power to use:", 
        user_input_3,
        plotOutput("plot_2")
        footer = tagList( actionButton(inputId = "submit_3", "Submit") )
      )
    )
    
    observeEvent(input$submit_3, {
                  . 
                  .
                  .
                  .
    })
  })
})

So I've tested this process out, and it works perfectly the first time through. However, if the user prompts this calculation a second time, that's where issues begin. The program will continue through the calculations regardless without prompting user input. I've looked a lot into this, and one of the references I found said that re-opening a modalDialog box will reset the actionButtons found in the dialog box. However, I think its this resetting that's triggering the observeEvents before the user is able to provide any input.

Is there another way that I can halt the progression through this series of modalDialogs until one of them is closed? Or is there another way that I can reset the actionButtons so that the observeEvents aren't automatically triggered immediately? I've tried everything through setting separate reactive values to removing and resetting the values of the actionButtons, but nothing seems to work.
I'd appreciate any feedback!

Hello,

Given you only provided some dummy code and not the actual example, I have to guess what is going on in the background in your app, but from the look of it it seems an issue with not using the correct variable types.

Notice how in "observeEvent input$submit_2" you use the variable 'first_calc'. This is just a normal R variable and not a reactive shiny one. That means that the first time it's created it will have the correct value, but will not change anymore after that if you run it again. To fix this, you need to create a reactiveVal instead and update that so it will work when you run it again.

See below a dummy example of mine where a variable gets passed along. Notice how the values can be changed the second time around.

library(shiny)

ui <- fluidPage(
  
  actionButton("start1", "Start!"),
  uiOutput("myResult")
)

server <- function(input, output, session) {
  
  passOn = reactiveVal()
  
  observeEvent(input$start1, {
    passOn(sample(1:50, 1))
    showModal(modalDialog(
      title = "Modal 1",
      numericInput("val1", "Choose a value", value = passOn()),
      footer = tagList(actionButton(inputId = "start2", "Continue"))
    ))
  })
  
  observeEvent(input$start2, {
    passOn(input$val1)
    showModal(modalDialog(
      title = "Modal 2",
      numericInput("val2", "Choose a value", value = passOn()),
      footer = tagList(actionButton(inputId = "start3", "Continue"))
    ))
  })
  
  observeEvent(input$start3, {
    passOn(input$val2)
    showModal(modalDialog(
      title = "Modal 3",
      numericInput("val3", "Choose a value", value = passOn()),
      footer = tagList(actionButton(inputId = "finished", "Finish!"))
    ))
  })
  
  observeEvent(input$finished, {
    removeModal()
    passOn(input$val3)
    output$myResult = renderUI({
      tags$h1(paste("The final value is", passOn()))
    })
  })
  
}

shinyApp(ui, server)

Hope this helps!
PJ

I just played with your example, and it functions exactly as I would like mine too. I've noticed in the example that you provided that you're observeEvents are separate: in my current (incorrect) implementation, the observeEvents are nested. Could that cause some of the complications as well, do you think?
Thanks for the reply!

Hi,

Definitely, observeEvents have an innate 'isolate' property, meaning they will only react to the trigger specified at the top, and all reactive values inside (including other events) will not refresh the code.

PJ

1 Like

It ended up working! There's no one else in my lab that has utilized shiny before, so I was so lost dealing with the reactive environment. Thanks for the feedback!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.