R Shiny - limit actionButton presses per second

43 views Asked by At

I'm doing some complex calculations in Shiny that the user starts via an ActionButton. However, I'm worried about users spamming the button a lot of times in a short while, which could bring up lots of unnecessary calculations. I've tried using debounce(), but it still registers all the button clicks. Here is a reprex:

library(shiny)

ui <- fluidPage(
  actionButton("start", "Press me")
)

server <- function(input, output, session) {
  new_number <- eventReactive(input$start, {
    print("Button press registered!")
    # sleep to imitate a long calculation
    Sys.sleep(1)
    runif(1, 1, 1000)
  }) %>% debounce(millis = 3000)
  
  observeEvent(new_number(),
               print(new_number()))
}

shinyApp(ui, server)

Try running the app and clicking as fast as you can.

It shows that the button registers as being pressed lots of times, each halting the process for the full amount of time.
The output value is only printed once and not as much as the button is clicked, which I suspect might be useful. But I can't figure out how to register, e.g., a maximum of one button press per second.

2

There are 2 answers

0
Stéphane Laurent On

One possibility is to use the onclick attribute of the button to disable the button whenever it is clicked, and re-enable it after the duration you want (3 seconds in the example below).

library(shiny)

onclick <- paste(
  "var btn = this;",
  "btn.setAttribute('disabled', 'disabled');", 
  "setTimeout(function(){btn.removeAttribute('disabled');}, 3000);"
)

ui <- fluidPage(
  actionButton(
    "start", 
    "Press me",
    onclick = onclick
  )
)
0
thekangaroofactory On

You could use observeEvent on input$start and keep the timestamp when it's clicked and do nothing if it's clicked again before the 3000ms timeout.

That being said, I would definitely recommend to disable the button from a user experience point of view.

library(shiny)

ui <- fluidPage(
  actionButton("start", "Press me")
)

server <- function(input, output, session) {
 
  # -- init
  ref_timestamp <- reactiveVal(0)
  
  observeEvent(input$start, {
  
    # -- get current timestamp (in milliseconds)
    timestamp <- as.numeric(Sys.time())*1000

    # -- check timestamp
    if(timestamp - ref_timestamp() > 3000){
      
      # -- store new timestamp
      ref_timestamp(timestamp)
      
      print("Button press registered!")
      
      # sleep to imitate a long calculation
      Sys.sleep(1)
      
      # -- compute
      print(runif(1, 1, 1000))}
    
  })
  
}

shinyApp(ui, server)