Skip to contents

Call this once, near the top of your server function. After that, rewind records the session inputs as the user works. It also records the reactive values that you register with rewind_track(). The user can then move backwards and forwards through that history.

Usage

rewind_enable(
  session = shiny::getDefaultReactiveDomain(),
  inputs = NULL,
  exclude = NULL,
  depth = 50L,
  coalesce_ms = 400L,
  shortcuts = TRUE,
  verbose = FALSE
)

Arguments

session

The Shiny session. The default is the current session.

inputs

Character vector of the input IDs to capture. Use NULL (the default) to capture all permitted inputs.

exclude

Character vector of input IDs to skip. rewind applies this after inputs.

depth

The maximum number of history entries to keep. rewind removes the oldest entries first.

coalesce_ms

The quiet period in milliseconds before rewind writes a change to the history. Increase it to group more changes.

shortcuts

Set to TRUE to bind the keyboard shortcuts in the browser. There are three:

  • Ctrl + Z (Cmd + Z on macOS) does an undo;

  • Ctrl + Shift + Z (Cmd + Shift + Z on macOS) does a redo;

  • Ctrl + Y also does a redo. This is the usual redo shortcut on Windows.

The shortcuts do nothing while the user types in a text field. The text undo of the browser thus continues to work.

verbose

Set to TRUE to show messages about what rewind captures and restores. This is useful during development.

Value

The controller, invisibly. Most applications can ignore it.

What gets captured

By default rewind captures every input in the session. There are four exclusions. It is never useful to restore these:

  • action buttons and links. Their value is a click counter.

  • shiny::fileInput(). Its value points to a temporary file on the server. Shiny deletes that file at the next upload. An old snapshot would thus point to a file that does not exist.

  • inputs with names that start with rewind_. These belong to this package.

  • inputs with names that start with .. These are internal to Shiny.

Use inputs to give a list of the inputs to capture. This is usually better in a large application. Undo must move the controls that the user thinks of as filters. It must not move every other input on the page.

Grouping

Changes that occur within coalesce_ms of each other become one history entry. One drag of a slider is thus one undo step, not forty. Use rewind_step() to group changes yourself.

Modules

You can call this function inside a moduleServer(). rewind captures the inputs with their module-local names. These are the same names that input$ uses inside the module. rewind adds the namespace with session$ns() when it restores them.

All modules share session$userData. A second call to rewind_enable() thus uses the same history as the first call. It does not make a second history. Call the function once, at the position in the module tree that is best for your application.

Examples

if (interactive()) {
  library(shiny)

  ui <- fluidPage(
    rewind_buttons(),
    selectInput("species", "Species", c("setosa", "versicolor", "virginica")),
    sliderInput("n", "Rows", 1, 50, 10),
    tableOutput("tbl")
  )

  server <- function(input, output, session) {
    rewind_enable()

    output$tbl <- renderTable({
      head(iris[iris$Species == input$species, ], input$n)
    })
  }

  shinyApp(ui, server)
}