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)
In Shiny, you express your server logic using reactive programming. Reactive programming is an elegant and powerful programming paradigm, but it can be disorienting at first because it’s a very different paradigm to writing a script.
This is the big idea in Shiny: you don’t need to tell an output when to update, because Shiny automatically figures it out for you. How does it work? What exactly is going on in the body of the function?
But Shiny performs the action every time we update input$name, so there must be something more going on. The app works because the code doesn’t tell Shiny to create the string and send it to the browser, but instead, it informs Shiny how it could create the string if it needs to. It’s up to Shiny when (and even if!) the code should be run.
This is why almost all of the reactive programming you’ll do in Shiny will be inside the server function 6 . Server functions take three parameters: input, output, and session . Because you never call the server function yourself, you’ll never create these objects yourself.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With