Reactive input in RShiny reacts too quickly (without using a button)

Viewed 202

How do I make it so that Shiny waits a little bit for the user to input their zip code (without using a button). The problem I'm facing is that it will quickly jump to the error if the user isn't fast enough at inputting their zip code. Edit:

  • I have other user inputs in this app, but I simplified it in this question. I want all of the other inputs to be reacted to right away since they are radioButtons. I think pressing 'return' would still do the same thing as a button, which isn't what I'm looking for. I was thinking about using ' Sys.sleep()' only for the zipcode input and not for the others. Would that be possible?
library(shiny)

shinyApp(ui <- fluidPage(sidebarPanel(
  "",
  textInput("zipcode", label = "Enter your zipcode.", value = 98125)
  
)) ,


server <- function(input, output, session) {
  observeEvent(input$zipcode, {
    #limits zipcode input to 5 numbers only
    if (nchar(input$zipcode) != 5)
    {
      updateTextInput(session, 'zipcode', value = 98125)
      showModal(
        modalDialog(
          title = "Error!",
          "Only 5-character entries are permitted.",
          easyClose = TRUE
        )
      )
    }
    if (is.na(as.numeric(input$zipcode)))
    {
      showModal(
        modalDialog(
          title = "Error!",
          "Only numeric values are allowed. Please try again.",
          easyClose = TRUE
        )
      )
    }
  })
})
2 Answers

You could use debounce:

This lets you ignore a very "chatty" reactive expression until it becomes idle, which is useful when the intermediate values don't matter as much as the final value

You don't need Sys.sleep, it will wait millis milliseconds before triggering the reactives :

library(shiny)

shinyApp(
  ui <- fluidPage( 
    sidebarPanel("", textInput("zipcode", label="Enter your zipcode.", value = 98125)
                 
    )  ) , 
  
  
  server <- function(input, output, session) {
    zipcode <- reactive(input$zipcode)
    zipcode_d <- debounce(zipcode, millis = 2000)
    observeEvent(zipcode_d(),{     #limits zipcode input to 5 numbers only
      if(nchar(zipcode_d())!=5)
      {
        updateTextInput(session,'zipcode',value=98125)
        showModal(modalDialog(
          title = "Error!",
          "Only 5-character entries are permitted.",
          easyClose = TRUE
        ))
      }
      if(is.na(as.numeric(zipcode_d())))
      {
        showModal(modalDialog(
          title = "Error!",
          "Only numeric values are allowed. Please try again.",
          easyClose = TRUE
        ))
      }
    }
    )
  })

JS code added, input$keyPressed which receives a random number when the "Return" key is pressed anywhere.

library(shiny)

js <- '
$(document).on("keyup", function(e) {
  if(e.keyCode == 13){
    Shiny.onInputChange("keyPressed", Math.random());
  }
});
'

shinyApp(ui <- fluidPage(tags$script(js),
                         sidebarPanel(
                           "",
                           textInput("zipcode", label = "Enter your zipcode.", value = 98125),
                           textOutput("zip")
                         )) ,
         
         server <- function(input, output, session) {
           observeEvent(input[["keyPressed"]], {
             #limits zipcode input to 5 numbers only
             if (nchar(input$zipcode) != 5)
             {
               updateTextInput(session, 'zipcode', value = 98125)
               showModal(
                 modalDialog(
                   title = "Error!",
                   "Only 5-character entries are permitted.",
                   easyClose = TRUE
                 )
               )
             }
             if (is.na(as.numeric(input$zipcode)))
             {
               showModal(
                 modalDialog(
                   title = "Error!",
                   "Only numeric values are allowed. Please try again.",
                   easyClose = TRUE
                 )
               )
             }
             output$zip <- renderText(input$zipcode)
           })
         })

linked to: Shiny Responds to Enter

Related