Prevent dynamically created UI elements from triggering observers upon app initialisation

Dynamically created UI items trigger event observers upon app initialisation. This might an undesirable behaviour in some instances. To avoid this, event observers compare current with previous state of the UI item. Only if a value has changed, further action is triggered. Upon app initialisation the values returned by input are equal to the default value within rv. Thus, no action is taken. Find below a minimal example. There might be more elegant solutions out there.

library(shiny)
library(rlang)

ui <- fluidPage(
  uiOutput("body"),
  textOutput("text")
)
server <- function(input, output, session) {
  
  # Initial state
  items <- list(dynamicBox = FALSE, slider = 5L) # "5L" !important
  
  # Default values (dynamic, not necessary in this example)
  rv <- exec(reactiveValues, !!!items)
  
  # Render UI
  output$body <- renderUI(
    tagList(
      checkboxInput("dynamicBox", "dynamicBox"),
      sliderInput("slider", value = 5L, min = 0L, max = 10L, step = 1L, label = "Slider")
    ))

  # Build event observers in a loop
  sapply(names(items), function(i){
    observeEvent(input[[i]], { 
      # Compare current with previous state
      if(!identical(rv[[i]], input[[i]])){
        output$text <- renderText({sprintf("Observer of %s is executed. Value = %s", i, isolate(input[[i]]))})
      }
      rv[[i]] <- input[[i]]
    })
  })

}
shinyApp(ui, server)

Created on 2020-02-18 by the [reprex package](https://reprex.tidyverse.org) (v0.3.0)</sup>

I have a similar issue. The situation is this:

  • I have a Shiny application with a number of tabs.
  • It also has a sidebar with widgets that allows you to set various configuration parameters.
  • Each tab has its own default values for these parameters.
  • When you switch to a new tab, the sidebar widgets should be programmatically updated to reflect the default values for that tab.
  • If you then change the settings in the sidebar, that will override the defaults for the current tab.

This more or less works, but the issue is that the initial tab is having the default overwritten. I traced through the order of events, and it seems to be the following:

  1. The widgets are set to their initial value.
  2. The initial tab's settings are set to their default value.
  3. The widgets are updated to reflect those default values.
  4. The tab's settings are overwritten by the initial values for the widgets in step 1.
  5. The widgets are updated to reflect the new tab settings.

So I want to prevent the update at step 4. If the widget is updated as an initialization step, then we don't want that to override the tab's defaults. If it's a user's interaction, then we do want to override the defaults. But it's difficult programmatically to distinguish between those cases.

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.