Edit: Found a proxy solution using updateQueryString
function that updates the url location bar. Basically what i did was to add one selectInput
inside the ui that displays all the bookmarks previously saved to let the user pick one to restore.
There are a few limitations for implementing restore with rds files. The first one is that input.rds (the file created by the bookmark) only displays the name and the value(s) of the input but not the type, so there's no way of telling if the value corresponds to an actionButton
or textInput
. Even if we implement a system for recognizing each type, some functions like updateActionButton
does not have a value
argument, so it's value will mostly never be correct.
library(shiny)
library(tidyverse)
get_last_bookmark <- function(){
list.files(path = 'shiny_bookmarks/') %>% #path to every folder containing bookmarked data.
map_df(., ~paste0('shiny_bookmarks/', .x) %>%
file.info ) %>%
slice_max(atime) %>%
rownames()
}
get_last_bookmark <- possibly(get_last_bookmark, otherwise = '') #avoid empty folder error
ui <- function(request){fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("data", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
fileInput("file1", "Choose RDA File", accept = ".rda"),
bookmarkButton(),
verbatimTextOutput('last_dir'),
br(),
selectInput('select_state', 'Select Bookmark Folder To Restore', choices = list.files(path = 'shiny_bookmarks/'),selected = get_last_bookmark() %>% str_sub(17, -1)),
actionButton('dorestore', 'Restore it!')
),
mainPanel(
tableOutput("data_head"),
tableOutput("contents"),
selectInput("select", "Select Variable", choices = NULL, selected = NULL),
plotOutput("boxplot")
)
)
)
}
server <- function(input, output, session) {
output$last_dir <- renderText({
paste0('The last bookmark is stored in: ', get_last_bookmark())
})
onBookmark(function(state){
output$last_dir <- renderText({
paste0('The last bookmark is stored in: ', get_last_bookmark())
})
updateSelectInput(session = session, 'select_state', choices = list.files(path = 'shiny_bookmarks/'), selected = get_last_bookmark() %>% str_sub(17, -1) )
state$values$input_value_to_restore <- input$select
})
onBookmarked(function(state){
#avoid showing message window
})
observeEvent(input$dorestore, {
updateQueryString(queryString = paste0('?_state_id_=', input$select_state), session = session)
session$reload()
})
dataset <- reactive({
file <- input$data
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
my_data <- read.csv(file$datapath, header = input$header)
my_data
})
output$data_head <- renderTable({
head(dataset())
})
output$boxplot <- renderPlot({
req(dataset())
req(input$select)
boxplot(dataset()[[input$select]], horizontal = TRUE)
})
observeEvent(input$data, { #this will cause input$select to reset when the app restores because of the way shiny restores the app.
req(dataset())
updateSelectInput(session = getDefaultReactiveDomain(), "select", label = "Select Variable", choices = c("", names(dataset())))
})
#avoid the dynamic parts of the app to reset
onRestored(function(state) {
updateSelectInput(session, 'select', selected = state$values$input_value_to_restore)
})
output$out <- renderText({
if (input$caps)
toupper(input$txt)
else
input$txt
})
output$contents <- renderTable({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "rds", "Please upload a RDA file"))
readRDS(file$datapath)
})
}
shinyApp(ui, server, enableBookmarking = "server")
This app will read the last created folder with the bookmark data and
print it's contents in a tab called "Rds From Last State"
library(shiny)
library(tidyverse)
ui <- function(request){fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("data", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
fileInput("file1", "Choose RDS File", accept = ".rds"),
bookmarkButton()
),
mainPanel(
tabsetPanel(
tabPanel('Tables',
tableOutput("data_head"),
tableOutput("contents"),
selectInput("select", "Select Variable", choices = NULL, selected = NULL),
plotOutput("boxplot")),
tabPanel('Rds From Last State',
verbatimTextOutput('bookmark_rds'))
)
)
)
)
}
server <- function(input, output) {
dataset <- reactive({
file <- input$data
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
my_data <- read.csv(file$datapath, header = input$header)
my_data
})
output$data_head <- renderTable({
head(dataset())
})
output$boxplot <- renderPlot({
req(dataset())
boxplot(dataset(), main = input$select, horizontal = TRUE)
})
observeEvent(input$data, {
req(dataset())
updateSelectInput(session = getDefaultReactiveDomain(), "select", label = "Select Variable", choices = c("", names(dataset())))
})
output$out <- renderText({
if (input$caps)
toupper(input$txt)
else
input$txt
})
output$contents <- renderTable({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "rds", "Please upload a RDS file"))
readRDS(file$datapath)
})
rds_directory <- reactiveValues()
onRestore(function(state) {
#The last modified folder inside the bookmarks directory will contain the latest values to restore.
last_bookmark_dir <-
list.files(path = 'shiny_bookmarks/') %>% #path to every folder containing bookmarked data.
map_df(., ~paste0('shiny_bookmarks/', .x) %>%
file.info ) %>%
slice_max(atime) %>% rownames()
print(paste('Last bookmark dir:', last_bookmark_dir))
print(list.files(last_bookmark_dir))
rds_directory$rds <- last_bookmark_dir %>%
list.files %>%
str_subset('\\.rds') %>% #subset all the .rds files
{paste0(last_bookmark_dir, '/', .)} %>% map(~ readRDS(.x))
print(rds_directory$rds)
})
output$bookmark_rds <- renderPrint({
req(rds_directory$rds) #If there's no bookmark this chunk won't execute
map(rds_directory$rds, ~ .x)
})
}
shinyApp(ui, server, enableBookmarking = "server")