rshinyshinyjsshinywidgets

Trigger observeEvent in Shiny even when condition hasn't changed


I am having some trouble getting the functionality in my app that I'm looking for because of the way observeEvent works (which is normally very intuitive).

The basic functionality I'm looking for is that a user can input a couple numbers, click "submit", and then a modal pops up to take the user's name. After that, the app records the name and sums the numbers, and then clears the inputs. Then I'd like the user to be able repeat the process using the same name - but the app currently is structured so that the sums use an observeEvent that responds only when the name is different (i.e., using the same name twice in a row doesn't work, though I'd like it to). You can see in the app that my attempt at a solution is to reset the input for the inputSweetAlert (using shinyjs), but it can't access it, I assume because it's not actually on the UI side. I am using shinyWidgets sweetAlerts, which I'd like to continue doing.

Here's an example app:

library("shiny")
library("shinyWidgets")
library("shinyjs")

ui <- fluidPage(
  shinyjs::useShinyjs(),
  numericInput("num1", "Enter a number", value=NULL),
  numericInput("num2", "Enter another number", value=NULL),
  actionButton(inputId = "go", label = "submit"),
  verbatimTextOutput(outputId = "res1"),
  verbatimTextOutput(outputId = "res2")
)

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

  observeEvent(input$go, {
    inputSweetAlert(session = session, inputId = "name", title = "What's your name?")
  })

  x <- reactiveValues(val=NULL)

  observeEvent(input$name, {
    x$val <- input$num1 + input$num2
    confirmSweetAlert(session = session, inputId = "confirmed", title = "Success!", text = "Your responses have been recorded. All is in order.", type = "success", btn_labels = c("Ok, let me continue")
    )
  })

  ## A possible approach to a solution...
  observeEvent(input$confirmed, {
    shinyjs::reset("num1") 
    shinyjs::reset("num2") 
    shinyjs::reset("name")
  })

  output$res1 <- renderPrint(paste("Name:", input$name))
  output$res2 <- renderPrint(paste("Sum:", x$val))
}

shinyApp(ui = ui, server = server)

Thanks for any help you can provide!


Solution

  • You can reset input$name via JS:

    runjs('Shiny.setInputValue("name", null, {priority: "event"});')
    

    Here is a working example:

    library("shiny")
    library("shinyWidgets")
    library("shinyjs")
    
    ui <- fluidPage(
      shinyjs::useShinyjs(),
      numericInput("num1", "Enter a number", value = NULL),
      numericInput("num2", "Enter another number", value = NULL),
      actionButton(inputId = "go", label = "submit"),
      verbatimTextOutput(outputId = "res1"),
      verbatimTextOutput(outputId = "res2")
    )
    
    server <- function(input, output, session) {
      
      observeEvent(input$go, {
        inputSweetAlert(session = session, inputId = "name", title = "What's your name?")
        runjs('Shiny.setInputValue("name", null, {priority: "event"});')
      })
      
      x <- reactiveValues(val = NULL)
      
      observeEvent(input$name, {
        x$val <- input$num1 + input$num2
        confirmSweetAlert(session = session, inputId = "confirmed", title = "Success!", text = "Your responses have been recorded. All is in order.", type = "success", btn_labels = c("Ok, let me continue"))
      })
      
      observeEvent(input$confirmed, {
        shinyjs::reset("num1") 
        shinyjs::reset("num2") 
        shinyjs::reset("mytext")
      })
      
      output$res1 <- renderPrint(paste("Name:", input$name))
      output$res2 <- renderPrint(paste("Sum:", x$val))
    }
    
    shinyApp(ui = ui, server = server)
    

    For further information please see this article.

    EDIT: In apps using modules, the call to runjs() can be adapted like this in order to namespace the id:

    runjs(paste0("Shiny.setInputValue(\"", ns("name"), "\", null, {priority: \"event\"});"))