mholopai
mholopai

Reputation: 73

Shiny: allow reactivity to be user-selectable

I'm building an app with several tabs, some which involve excessive calculations and others that calculate quickly. A checkbox which would allow the user to choose between reactivity or manual updating, in combination with a "refresh"-button, would be ideal.

The simple example below illustrates what I'm aiming for. It nearly works, except for one final refresh when the "Automatically refresh"-checkbox is unchecked, which is a pain, should a computationally intensive tab be open. Is there any way around this?

ui.r

library(shiny)
shinyUI(fluidPage(
    titlePanel("Test"),
    sidebarLayout(
        sidebarPanel(
            checkboxInput("autoRefresh", "Automatically refresh", TRUE),
            actionButton("refresh", "Refresh!"),
            radioButtons("choice", "Choice of value:",
                c("10" = 10,
                "20" = 20))
            ),

        mainPanel(
            tabsetPanel(type = "tabs", 
                tabPanel("Add random decimals to value", textOutput("value"))
            )
        )
    )
))

server.r

library(shiny)
shinyServer(function(input, output) {
    output$value <- renderText({

        input$refresh
        if(input$autoRefresh == 1) {
            input$choice
        }
        isolate({
            output <- runif(1,0,1) + as.numeric(input$choice)
        })
    })
})

Many thanks in advance!

Upvotes: 7

Views: 232

Answers (2)

John Paul
John Paul

Reputation: 12664

In this solution, I made two observers: one for when the refresh button is hit and a second for when choice is changed. The first always updates the output.

The second checks the status of input$autoRefresh and then either just exits or updates the renderText.

Unfortunately you must have the runif command written twice, which can be bad for updating your code (easier to introduce errors if you are doing something twice). In practice you might want to make a new function and then just call that function if this is a complex/multi-line process in your actual app.

  shinyServer(function(input, output) {
    observe({
      input$refresh
      output$value<-renderText({
        isolate(runif(1,0,1) + as.numeric(input$choice))
        })
      })
    observe({
      input$choice
      output$value<-if(input$autoRefresh==0) return() else {
          renderText({isolate(runif(1,0,1) + as.numeric(input$choice))})
      }  
    })
  })

Upvotes: 2

hedgedandlevered
hedgedandlevered

Reputation: 2394

You could cache the output and shortcut-return it when appropriate

library(shiny)
shinyServer(function(input, output) {
  output$value <- renderText({

    input$refresh
    if(input$autoRefresh == 1) {
      input$choice
    } else return(cachedOutput)
    isolate({
      cachedOutput <<- output <- runif(1,0,1) + as.numeric(input$choice)
    })
  })
})

Upvotes: 2

Related Questions