Learn R Programming

rewind (version 0.3.0)

rewind_enable: Enable undo and redo for a Shiny session

Description

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,
  restore_timeout = 2,
  shortcuts = TRUE,
  verbose = FALSE
)

Value

The controller, invisibly. Most applications can ignore it.

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.

restore_timeout

The time in seconds that rewind waits for the browser to finish a restore. The default of 2 suits a fast connection.

Increase it for an application on a slow connection, such as one behind a VPN or on a mobile network. If the limit is too short, capture starts again while the browser is still applying the restore, and a partial state becomes a history entry that the user never made.

Do not increase it more than you need. If a restore never returns, rewind ignores the changes of the user until this limit ends.

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.

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

Run this code
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)
}

Run the code above in your browser using DataLab