Note: After coming up with the answer I reworded the question to make if clearer.
Sometimes in a shiny
app. I want to make use of a value s
Seeing as the session flush event method seems to be broken for this purpose, here is an alternative way to do it using an observeEvent
construct and a reactive variable.
library(shiny)
ui <- fluidPage(
h1("Memory"),
sidebarLayout(
sidebarPanel(
numericInput("val", "Next Value", 10)
),
mainPanel(
verbatimTextOutput("curval"),
verbatimTextOutput("lstval")
)
)
)
server <- function(input,output,session) {
rv <- reactiveValues(lstval=0,curval=0)
observeEvent(input$val, {rv$lstval <- rv$curval; rv$curval <- input$val})
curre <- reactive({req(input$val); input$val; rv$curval})
lstre <- reactive({req(input$val); input$val; rv$lstval})
output$curval <- renderPrint({sprintf("cur:%d",curre())})
output$lstval <- renderPrint({sprintf("lst:%d",lstre())})
}
options(shiny.reactlog = TRUE)
shinyApp(ui, server)
Yielding:
Update This answer was posted before the advent of the reactiveValues
/observeEvent
model in shiny
. I think that @MikeWise 's answer is the better way to do this.
After some playing around this is what I came up with. The ui.r is nothing special
ui.r
library(shiny)
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectizeInput(inputId="XX", label="Choose a letter",choices=letters[1:5])
),
mainPanel(
textOutput("Current"),
textOutput("old")
)
)
))
"Current"
will display the current selection and "old"
displays the previous selection.
In the server.r
I made use of three key functions: reactiveValues
, isolate
and session$onFlush
.
server.r
library(shiny)
server <- function(input, output,session) {
Values<-reactiveValues(old="Start")
session$onFlush(once=FALSE, function(){
isolate({ Values$old<-input$XX })
})
output$Current <- renderText({paste("Current:",input$XX)})
output$old <- renderText({ paste("Old:",Values$old) })
}
The server.r
works like this.
First, Values$old
is created using the reactiveValues
function. I gave it the value "Start" to make it clear what was happening on load up.
Then I added a session$onFlush
function. Note that I have session
as an argument in my server
function. This will run every time that shiny flushes the reactive system - such as when the selectizeInput
is changed by the user. What is important is that it will run before input$XX
gets a new value - so the value has changed at the selectizeInput
but not at XX
.
Inside the session$onFlush
I then assign the outgoing value of XX
to Values$old
. This is done inside an isolate()
as this will prevent any problems with input$XX
gets updated with the new values. I can then use input$XX
and Values$old
in the renderText()
functions.