Search code examples
rshinyshiny-reactivityobservers

How to pass reactive values between observers?


In the code posted at the bottom, I'm trying to cap the value of the second reactive object (y) at the value of the first reactive object (x) using two observeEvents() as action button click counters, as explained in the illustration below. The illustration shows the results of clicking the "Pos" button 3 times and the "Neg" button 4 times. How would this be done?

I commented-out one of my attempts in the below code.

Illustration:enter image description here

Code:

library(shiny)

ui <-  fluidPage(br(),
  actionButton("Btn1", "Pos"),
  actionButton("Btn2", "Neg"),
  br(),br(),
  textOutput("posClicks"),
  textOutput("negClicks"),
  textOutput("netClicks")
)

server <- function(input, output, session) {
  
  x = reactiveVal(0)
  y = reactiveVal(0)
  
  observeEvent(input$Btn1,{x(x()+1)})
  observeEvent(input$Btn2,{y(y()+1)})
  
  # below is commented-out because it gives strange results counting in leaps of 2's
  # observeEvent(input$Btn2,{
  #   if(x()-y(y()+1) >= 0){y(y()+1)}
  #   })
  
  output$posClicks <- renderText({paste('Pos clicks =',x())})
  output$negClicks <- renderText({paste('Neg clicks =',y())})
  output$netClicks <- renderText({paste('Net clicks =',x()-y())})
  
}

shinyApp(ui, server)

Solution

  • If you really need to have two separate observes, you could do

      observeEvent(input$Btn1,{x(x()+1)})
      observeEvent(input$Btn2,{y(y()+1)})
      observe({
         if (y()>x()) {y(x())}
      })
    

    Rather than listening for clicks on the button, you just observe the value of y() and if it gets bigger than x(), just reset it. If you can, it would be easier just to change the Btn2 logic

      observeEvent(input$Btn1,{x(x()+1)})
      observeEvent(input$Btn2,{y(min(y()+1, x()))})