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:

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 StackOverflow 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

You are misunderstanding. The eventReactive runs only with button press. However what it runs establishes a reactive render formula that will itself update based on input$x changes. Just as if you hadn't wrapped it in eventReactive. I.e. your button sets up a formula, the formula has its own life. Once it's alive it goes

Not sure what else to say, other than it is bad practice to define an output object inside an observe or an observeEvent. That is something I've learned through practice, yet was also noted in a comment on this SO post: r - Shiny: what is the difference between observeEvent and eventReactive? - Stack Overflow. For some reason, this always stuck in my mind.

In case that link is removed in the future, the comment references a post from Joe Cheng in 2016 regarding Effective Shiny Programming, and how NOT to solve the problem of plotting in Shiny.

Anti-solution

observe({
  df <- head(cars, input$nrows)
  output$plot <- renderPlot(plot(df))
})

"This pattern of putting renderPlot inside of an observe, usually means the author has a fundamental misconception of what it means to assign a render code block to an output slot."

This answer on StackOverflow explained it: r - observeEvent triggered by events in the handling expression, rather than just the eventExpr trigger - Stack Overflow

Ok good to get a quasi official opinion on this practice.

The reason I started doing this was actually inspired by a different answer to the same StackOverflow question. The one with the two code snippets. By adding observeEvent to the second one I was able to make it work. But now I understand why this is not the best practice.

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

If you have a query related to it or one of the replies, start a new topic and refer back with a link.