--- title: "Snapshots and bookmarks" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Snapshots and bookmarks} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` Shiny's bookmarking (`enableBookmarking()`) and shinysnap both let users return to a saved state. This vignette helps you choose between them, use them together, or switch an app from bookmarks to snapshot files. ## What each one does | | bookmarking | shinysnap | |---|---|---| | where state is saved | a URL (`"url"`) or a server directory (`"server"`) | a file the user downloads and uploads | | how it restores | opens the URL in a new session | restores the current session without reloading | | dynamic inputs | receive saved values when created, through `restoreInput()` | receive saved values when created or when they appear in the browser | | setup | a UI function and `enableBookmarking()` | no required UI changes | | file contents | JSON encoded in a URL, or `.rds` files | JSON you can read in a text editor | | support for app changes | no migration helpers | app name and version, `validate` and `migrate` hooks, and a restore report | Use bookmarking when you want to send a colleague a link to what you're looking at. Use shinysnap when you want to save your work to a file and return to it later, perhaps after the app has been updated. ## Using both You can add shinysnap to an app that already uses bookmarking: - Ids excluded with `setBookmarkExclude()` are excluded from snapshots too. - Values that Shiny marks as unserializable, such as passwords, are never saved. This includes values excluded by a serializer registered with `setSerializer()`. - During a restore, shinysnap makes the snapshot's values available to `restoreInput()`, which supplies initial values to new inputs. It restores the previous settings when the restore finishes. - shinysnap's own internal inputs are marked unserializable, so they never show up in a bookmark URL. The callbacks, or *hooks*, work similarly in both packages. `onBookmark(function(state) ...)` and `snap_on_save()` write to `state$values`. `onRestore()` and `snap_on_restore()` read the saved values. If you use `reactiveValues`, `snap_track()` can save and restore them for you. ## Turning a snapshot into a bookmark Use `snap_as_bookmark_url()` to turn a snapshot into a link. The app must use `enableBookmarking("url")` and a UI function to open it: ```{r} library(shinysnap) snap <- list( inputs = list(n = 100L, model = "complex", weights = c(0.5, 0.75)), values = list(note = "baseline") ) snap_as_bookmark_url(snap, base_url = "https://example.org/app/") ``` Inside a server function, pass `session` instead of `base_url` to use the app's current address. The result uses the same `_inputs_` and `_values_` keys and encoding as a URL created by `session$doBookmark()`. ## Migrating an app 1. Remove `enableBookmarking()` and `bookmarkButton()`. Add `snap_download_button()` and `snap_file_input()` to the UI, and `snap_download_handler()` and `snap_file_restore()` to the server function. The UI no longer needs to be a function. 2. Replace `onBookmark()` hooks with `snap_on_save()`, and `onRestore()` hooks with `snap_track()` for `reactiveValues` (they are written back for you) or `snap_on_restore()` for anything else. 3. Keep `setBookmarkExclude()` calls; add `snap_enable(exclude = ...)` patterns for ids that should never be saved. 4. Give the app a name and a version with `snap_enable()`, and write a `migrate` hook the first time a saved value changes meaning. 5. In `shiny::testServer()` tests, use `snap_as_test_inputs()` to prepare the saved inputs for a `session$setInputs()` call.