shiny: Update input without reactives getting triggered?
Asked Answered
S

2

9

Is there any possibility to update an input without reactives getting triggered?

Below I put a minimal example. The aim is to update the slider without the value in the main panel changing. When the slider is changed again, then it should be forwarded to dependent reactives again.

The question and the underlying use case is similiar to the following questions: R shiny - possible issue with update***Input and reactivity and Update SelectInput without trigger reactive?. Similiar to these questions, there is a reactive that depends on two Inputs in my use case. I want to update one of these input depending on the other, which results in the reactive getting calculated twice. However, both of these questions got around the problem by updating the input only selectively. This is not possible in my use case, since I want to have some information shown to the user by updating the input.

If there is no possibility to update an input without reactives getting triggered, I will ask a follow-up-question focusing on my use case.

Example

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) {
   output$sliderValue <- renderText(input$bins) 

   observeEvent(input$set1,{
     updateSliderInput(session,"bins",value=20)
   })
   observeEvent(input$set2,{
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
     isolate(
       updateSliderInput(session,"bins",value=20 )
       )
   })
}

shinyApp(ui = ui, server = server)
Seka answered 6/2, 2019 at 18:39 Comment(0)
G
4

Here's a stab, though it feels like there might be side-effects from using stale data. Using the following diff:

 # Define server logic
 server <- function(input, output, session) {
-  output$sliderValue <- renderText(input$bins)
+  output$sliderValue <- renderText({ saved_bins(); })

+  update <- reactiveVal(TRUE)
+  saved_bins <- reactiveVal(30)
+
+  observeEvent(input$bins, {
+    if (update()) saved_bins(input$bins) else update(TRUE)
+  })
   observeEvent(input$set1,{
     updateSliderInput(session,"bins",value=20)
   })
   observeEvent(input$set2,{
     ## Is there any possibility to update the slider without 'sliderValue' changing?
     #isolate does not work
+    update(FALSE)
-    isolate(
       updateSliderInput(session,"bins",value=20 )
-    )
   })
 }

The method: using two new reactive values, one to store the data that (saved_bins) is used in the rendering, and one (update) to store whether that data should be updated. Everything that depends on input$bins should instead depend on saved_bins(). By using an additional observeEvent, the reactivity will always cascade as originally desired except when you explicitly set a one-time "do not cascade" with the prepended update(FALSE).

Full code below:

library(shiny)

ui <- fluidPage(
   titlePanel("Update Slider - Isolate reaction?"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         actionButton("set1", "set slider 'bins'$value=20"),
         actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
      ),

      mainPanel(
         textOutput("sliderValue")
      )
   )
)

# Define server logic 
server <- function(input, output, session) {
  output$sliderValue <- renderText({ saved_bins(); }) 

  update <- reactiveVal(TRUE)
  saved_bins <- reactiveVal(30)

  observeEvent(input$bins, {
    if (update()) saved_bins(input$bins) else update(TRUE)
  })
  observeEvent(input$set1,{
    updateSliderInput(session,"bins",value=20)
  })
  observeEvent(input$set2,{
    ## Is there any possibility to update the slider without 'sliderValue' changing?
    #isolate does not work
    update(FALSE)
    updateSliderInput(session,"bins",value=20)
 })
}

shinyApp(ui = ui, server = server)
Gelsenkirchen answered 6/2, 2019 at 19:5 Comment(2)
Cool. Although I wonder a little bit how costly the extra observer will be in the end... Maybe on the long run it might be a possibility to include this directly in the updateXXXInput-commands? At least I added it to the wish list: github.com/rstudio/shiny/issues/2324Seka
I understand your concern, though it is a "simple" 1-dimensional in-the-middle observe, if that makes sense. As long as nothing else reacts to input$bins, I think the risks of double-reactivity are minimal if not zero.Gelsenkirchen
E
0

Firstly credit to @r2evans's solution.

At the risk of a verbal thrashing from the many headteacheRs that prohibit it, to avoid double observer you can use global assignment. Sensible to use a less generic name than 'update' though.

library(shiny)

ui <- fluidPage(
  titlePanel("Update Slider - Isolate reaction?"),
  
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      actionButton("set1", "set slider 'bins'$value=20"),
      actionButton("set2", "'ISOLATED' set slider 'bins'$value=20 ")
    ),
    
    mainPanel(
      textOutput("sliderValue")
    )
  )
)

# Define server logic 
server <- function(input, output, session) {
  output$sliderValue <- renderText({ saved_bins(); }) 
  
  saved_bins <- reactiveVal(30)
  
  observeEvent(input$bins, {
    if (update) saved_bins(input$bins) else update <<- TRUE
  })
  observeEvent(input$set1,{
    updateSliderInput(session,"bins",value=20)
  })
  observeEvent(input$set2,{
    ## Is there any possibility to update the slider without 'sliderValue' changing?
    #isolate does not work
    update <<- FALSE
    updateSliderInput(session,"bins",value=20)
  })
}

shinyApp(ui = ui, server = server)
Eggbeater answered 15/10, 2020 at 22:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.