Difference between lapply and for loops in creating dynamic observers

I have always wondered, why we must use lapply instead of for loops to create dynamic observers. Let's say that I am inserting 5 buttons on a click of another button and create 5 observeEvents respectively to react to each button click.
When I use an equivalent for loop instead of a lapply, only the last observeEvent (5th button) is triggered (but 5x times for some reason). When I use a lapply, all buttons react once upon corresponding clicks. I wonder, why this is the case? What is the logic behind this?

# An example based on http://shiny.rstudio.com/articles/dynamic-ui.html

library(shiny)

ui = basicPage(
  fluidRow(
    actionButton(inputId = "add_buttons", label = "Add 5 Buttons")
  ),
  uiOutput("more_buttons") # this is where the dynamically added buttons will go.
)

server = function(input, output)
{
  # We need to track the actionButtons and their respective observeEvents
  rvs = reactiveValues(buttons = list(), observers = list()) 
  
  observeEvent(input$add_buttons,{
    l = length(rvs$buttons) + 1
    
    for(i in l:(l+4)) {
      rvs$buttons[[i]] = actionButton(inputId = paste0("button",i), label = i)
    }
    
    #rvs$observers = lapply(
     for(i in l:(l+4)){ 
      #function(i) {
     	rvs$observers[[i]] = observeEvent(input[[paste0("button",i)]], 
                     print(sprintf("You clicked button number %d",i))
        )
      }
    #)
    browser()
  }
  )
  
  output$more_buttons = renderUI({
    do.call(fluidRow, rvs$buttons) # Add the dynamic buttons into a single fluidRow
  })
}

shinyApp(ui, server)

Based on this example here: https://gist.githubusercontent.com/mine-cetinkaya-rundel/0fe2a9830f7151e72053239e73350592/raw/56eebeb5e854ef2cb55133eef543c2cd51b5dede/app.R

2 Likes

Please see this:

and this:

2 Likes

To prove the point mentioned in the references stackoverflow asnwer, I set i = 1 right after the loop and yes, now it triggers exactly only when the first button is pressed (5x times!) instead of the last button.

1 Like