简体   繁体   中英

How to listen for more than one event expression within a Shiny observeEvent

I want two different events to trigger an observer. It was suggested here that this should work. But it seems that it depends only on the second event.

observeEvent({ 
  input$spec_button
  mainplot.click$click
}, { ... } )

Have a look at the example.

ui <- shinyUI(bootstrapPage(
    actionButton("test1", "test1"),
    actionButton("test2", "test2"))
)

server <- shinyServer(function(input, output) {
    observeEvent({
        input$test1
        input$test2
    }, {
        print('Hello World')
    })
})

shinyApp(ui, server)

Once you click button test1 nothing happens. If you click button test2 it prints to your console. Once test2 button was pressed clicking test1 prints the message. That is a strange behaviour.

Another suggestion in that link was to use

list(input$test1, input$test2)

Which prints the message even without clicking the buttons.

This should do it, note that you still have to check if the buttons were clicked as mentioned by @MrFlick

1. You can use reactive expression

#rm(list = ls())
library(shiny)
ui <- shinyUI(bootstrapPage(
  actionButton("test1", "test1"),
  actionButton("test2", "test2"))
)

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

  toListen <- reactive({
    list(input$test1,input$test2)
  })
  observeEvent(toListen(), {
    if(input$test1==0 && input$test2==0){
      return()
    }
    print('Hello World')
  })
})

shinyApp(ui, server)

2. As per example given by @MrFlick (now deleted)

#rm(list = ls())
library(shiny)
ui <- shinyUI(bootstrapPage(
  actionButton("test1", "test1"),
  actionButton("test2", "test2"))
)

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

  observeEvent(input$test1 | input$test2, {
    if(input$test1==0 && input$test2==0){
      return()
    }
    print('Hello World')
  })
})

shinyApp(ui, server)

Using the | operator in the observeEvent() eventExpr won't work if the inputs are not numeric, logical or complex types.

For example, notice the message at the end of running this simple Shiny app with an actionButton() and a selectInput() used inside the observeEvent() eventExpr :

library(shiny)

ui <- shinyUI(bootstrapPage(
  selectInput("test1", "test1", choices = c("a", "b")),
  actionButton("test2", "test2"))
)

server <- shinyServer(function(input, output) {
  
  observeEvent(input$test1 | input$test2,
  {
    print('Hello World')
  })
})

shinyApp(ui, server)
#> 
#> Listening on http://127.0.0.1:6563
#> Warning: Error in |: operations are possible only for numeric, logical or
#> complex types

Created on 2022-04-02 by the reprex package (v2.0.1)

Instead, you can create a vector of the inputs inside the observeEvent() and include ignoreInit = TRUE if you wish to not print "Hello World" on app initialization. This approach accommodates any input types.

library(shiny)
ui <- shinyUI(bootstrapPage(
  selectInput("test1", "test1", choices = c("a", "b")),
  actionButton("test2", "test2"))
)

server <- shinyServer(function(input, output) {
  
  observeEvent(ignoreInit = TRUE, c(
    input$test1,
    input$test2
  ),
  {
    print('Hello World')
  })
})

shinyApp(ui, server)

If the observeEvent(c(input$a, input$b), {...}) approach doesn't float your boat, then I can recommend the reactive({list(input$a, input$b}) approach which goes like this:

library(shiny)
ui <- shinyUI(bootstrapPage(
  selectInput("test1", "test1", choices = c("a", "b")),
  actionButton("test2", "test2"))
)

server <- shinyServer(function(input, output) {
  
  event_trigger <- reactive({
    list(input$test1, input$test2)
  })
  
  observeEvent(ignoreInit = TRUE, event_trigger(),
  {
    print('Hello World')
  })
})

shinyApp(ui, server)

This approach has the advantage of being portable, meaning you can use it as the eventExpr for multiple observeEvent() calls (or other listeners) if needed.

observeEvent is a wrapper for complex observe cases. In this particular case of an action when one or other reactive value changes, one could use a simple observe. This works:

require(shiny)    
ui <- basicPage(
      actionButton("test1", "test1"),
      actionButton("test2", "test2")
    )
    
    server <- function(input, output, session){
    
      observe( {
        input$test1
        input$test2
        if(input$test1==0 && input$test2==0){
          return()
        }
        print('Hello World')
        })
    }
    
    shinyApp(ui, server)

There is a point in using observeEvent with options to eliminate the return() call:

ui <- basicPage(
  actionButton("test1", "test1"),
  actionButton("test2", "test2")
)

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

  observeEvent(input$test1 | input$test2, { print('Hello World') } , ignoreInit = TRUE)
}

shinyApp(ui, server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM