Jordan Mandel
Jordan Mandel

Reputation: 498

observeEvent triggered by events in the handling expression, rather than just the eventExpr trigger

The handling expression in the observeEvent in this reprex at first waits for the trigger button, but then is run whenever the input x in the 'Value" field is changed, not waiting for the trigger button.

library(shiny)

ui = fluidPage(
    column(12,
                 textInput("x", "Value","starting_text"),
                 br(),
                 actionButton("button", "trigger eventReactive!"),
                 h3("The textOutput below should only update when you click the button but after the first click it reacts directly to the textInput field"),
                 textOutput("out_text")
    )
)

server = function(input, output,session) {
    
    observeEvent(input$button, {
        output$out_text <-  renderText( input$x)
    })
    
}

shinyApp(ui,server)

I can solve this problem using an eventReactive or answers from this very similar Stack Overflow question: R Shiny observeEvent continues to trigger

There are answers there solving this problem by assigning input_value to a dummy variable inside of the handling expression, and by using isolate() around input$input_value with no for why they work. I can also solve this problem with an intermediate eventReactive.

So I'm still not satisfied. I think that my reprex and the one on the other question should just work as posted.

So either there is a fundamental bug in shiny, or as is usually the case, I'm misunderstanding something deeper. Or maybe this is a bug, but fixing it would break existing shiny apps that rely on this behavior?

To sum up: Can someone explain why the eventReactive gets run even though the triggering event does not occur? Can someone also explain why the two answers on StackOverflow work, especially the one with the assignment to the Dummy variable?

Finally I'll mention that there may be other questions here and on StackOverflow regarding this issue, but I did not find the reprexes to be sufficiently minimal or easy to digest

Upvotes: 2

Views: 595

Answers (1)

Waldi
Waldi

Reputation: 41220

The recommended & working pattern in this situation is :

library(shiny)

ui = fluidPage(
  column(12,
         textInput("x", "Value","starting_text"),
         br(),
         actionButton("button", "trigger eventReactive!"),
         h3("The textOutput below should only update when you click the button but after the first click it reacts directly to the textInput field"),
         textOutput("out_text")
  )
)

server = function(input, output,session) {

  output$out_text <- renderText({
    input$button
    isolate(input$x)
  })
  
}

shinyApp(ui,server)

I find the comment from Romain François from tidyverse dev team on this post useful :

This is very "unshiny" to alter an output inside an observe. You'd rather typically set an output only once with a reactive expression

This gives the reason for the problem you encountered : each time you click on the button, you re-create a reactive object dependent on input$x. This object is then independent of the observeEvent itself.

Upvotes: 1

Related Questions