Search code examples
rshinyshinyjs

How to fire an event on edit only, not on update in Shiny


I want to enable a Save button when a control is edited by the user, but not when its state is loaded by update.... I know of js functions shiny:updateinput and shiny:inputchanged: the latter fires on all changes, the first on updatexxx only`. There seem to be no function "shiny:onuseredit".

library(shiny)
library(shinyjs)


ui <- fluidPage(
  useShinyjs(),
  tags$script(HTML("$(document).on('shiny:updateinput', function(event) {
         {console.log(event.target.id);}});")),
  tags$script(HTML("$(document).on('shiny:inputchanged', function(event) {
         {console.log(event.name);}});")),
  # No choices here, these will be loaded from db
  selectInput("group", "Group", choices = NULL),
  numericInput("nruns", "Number of runs", value = NULL),
  actionButton("load", "Load", class = "btn-info"),
  actionButton("save", "Save", class = "btn-success")
)

server <- function(input, output) {
  disable("save")

  observeEvent(input$load,{
    # In a real app, this will be loaded from a database
    updateSelectInput(inputId = 'group', choices = c("first", "second", "third"),
                      selected = "second")
    updateNumericInput(inputId = 'nruns', value = 10)

  })


  ## Missing code
  # How to enable the button on edits only, not on load from database
}
shinyApp(ui = ui, server = server)

Solution

  • It's a bit of a hack, but you can create a serverside flag if the change was due to loading the state or a user edit and listen for changes in the inputs:

    server <- function(input, output) {
      disable("save")
      update_flag <- reactiveValues(updated = "no")
      
      observeEvent(input$load,{
        # In a real app, this will be loaded from a database
        updateSelectInput(inputId = 'group', choices = c("first", "second", "third"),
                          selected = "second")
        updateNumericInput(inputId = 'nruns', value = 10)
        update_flag$updated <- "yes"
      })
      
      observeEvent(c(input$group, input$nruns), {
        if (update_flag$updated == "no") {
          enable("save")
        } else {
          update_flag$updated <- "no"
        }
      }, ignoreInit = TRUE)
    }