Use Variable for observeEvent eventExpr

354 views
Skip to first unread message

Dario Strbenac

unread,
Jun 29, 2016, 3:00:09 AM6/29/16
to Shiny - Web Framework for R
The following code does not work as intended, because only the observer for the third button has any effect and prints the output of both of the Show buttons. How can it be modified to work ? Could an example similar to this be added to the bottom of the help page to help less expert users ? If I don't use variables, then it works as expected.

library(shiny)

observerList <- list()

server <- shinyServer(function(input, output)
{
  observeEvent(input[["add"]], {
   
    addToButton <- "listen1"
    observerList <<- observeEvent(input[[addToButton]], print(2))
    addToButton <- "listen2"
    observerList <<- c(observerList, observeEvent(input[[addToButton]], print(3)))
  })
})

ui <- fluidPage(
  actionButton("add", "Add Observers"),
  actionButton("listen1", "Show 2"), # Nothing printed, but 2 should be.
  actionButton("listen2", "Show 3")  # 2 and 3 printed, although only 3 should be printed.
)

shinyApp(ui = ui, server = server)

Bárbara Borges

unread,
Dec 8, 2016, 6:17:22 PM12/8/16
to Shiny - Web Framework for R
This is scoping problem (by the way, this has to do with general scoping rules for R, not shiny in particular). Since the observers are lazily evaluated, both of those observers exist long after the code in the server has been run. By then, only the last reference to the `addToButton` variable (`addToButton <- "listen2"`) has been kept. There are two common ways around this (both of these capture local variables in a type of closure so that they remain accessible after the code has run):

1) the more quick and dirty type: use `local()`:


library(shiny)

server <- function(input, output, session) {
  
  observerList <- list()
  
  observeEvent(input[["add"]], {
    
    local({
      addToButton <- "listen1"
      observerList <<- observeEvent(input[[addToButton]], print(2))
    })
    local({
      addToButton <- "listen2"
      observerList <<- c(observerList, observeEvent(input[[addToButton]], print(3)))
    })
  })
}

ui <- fluidPage(
  actionButton("add", "Add Observers"),
  actionButton("listen1", "Show 2"), # Nothing printed, but 2 should be.
  actionButton("listen2", "Show 3")  # 2 and 3 printed, although only 3 should be printed.
)

shinyApp(ui = ui, server = server)


2) the scalable but more elaborate type: use lapply (or another apply/functional)


library(shiny)

server <- function(input, output, session) {
  
  observerList <- list()
  
  observeEvent(input[["add"]], {
    
    btns <- c('listen1' = 2, 'listen2' = 3)
    
    sapply(names(btns), function(name) {
      observerList <<- c(observerList, 
                         observeEvent(input[[name]], print(btns[[name]])))
    }, simplify = FALSE, USE.NAMES = TRUE)
  })
}

ui <- fluidPage(
  actionButton("add", "Add Observers"),
  actionButton("listen1", "Show 2"),
  actionButton("listen2", "Show 3")
)

shinyApp(ui = ui, server = server)


See this thread to learn more about this: https://github.com/rstudio/shiny/issues/532
Reply all
Reply to author
Forward
0 new messages