I want to design a shiny app that allow the users to save their inputs in the local storage, which means when the users reopen the tool with their web browsers, the tool reload the values last time the users provide. This is mainly achieved by the shinyStore package.
Below is an example. So far I can use the shinyStore
to restore any shiny input widget, such as textInput
. However, I now want to also restore the edited values in a datatable from the DT
package.
I know the information of the edited values are in the input$DT_out_cell_edit
, but it is not a single value, so the updateStore
function would not work. I thought about using dataTableProxy
and replaceData
from the DT
package, but they cannot keep values from the last time when the app runs. Finally, I tried to set stateSave = TRUE
as in this example, but it cannot document the edited values.
If possible, please let me know if you have any ideas. If it is not possible, please also let me know.
library(shiny) library(DT) library(shinyStore) ui <- fluidPage( headerPanel("shinyStore Example"), sidebarLayout( sidebarPanel = sidebarPanel( initStore("store", "shinyStore-ex1"), # A button to save current input to local storage actionButton("save", "Save", icon("save")), # A button to clear the input values and local storage actionButton("clear", "Clear", icon("stop")) ), mainPanel = mainPanel( fluidRow( textInput(inputId = "text1", label = "A text input", value = ""), DTOutput(outputId = "DT_out") ) ) ) ) server <- function(input, output, session) { output$DT_out <- renderDT( datatable( mtcars, selection = "none", editable = TRUE, options = list( stateSave = TRUE ) ) ) # Update the input with local storage when the app runs observe({ if (input$save <= 0){ updateTextInput(session, inputId = "text1", value = isolate(input$store)[["text1"]]) } updateStore(session, name = "text1", isolate(input$text1)) }) # Clear the local storage observe({ if (input$clear > 0){ updateTextInput(session, inputId = "text1", value = "") updateStore(session, name = "text1", value = "") } }) } shinyApp(ui, server)
Advertisement
Answer
Please check the following:
Im using a reactiveValue uiTable
to track the changes made to the datatable.
Once the save button is clicked updateStore
is used to save the data.frame
.
When a new session starts input$store$uiTable
is monitored for changes. If the table was changed it is updated via replaceData
.
For now this doesn’t work for the rownames of a data.frame
, as it needs some extra code, which in my eyes isn’t necessary to illustrate the principle.
Edit: I added the mtcars
rownames as a column via data.table
and disabled editing for the DT rownames to provide a more intuitive example for future readers.
library(shiny) library(DT) library(shinyStore) library(data.table) mtcarsDT <- data.table(mtcars, keep.rownames = TRUE) cols <- names(mtcarsDT) mtcarsDT[, (cols) := lapply(.SD, as.character), .SDcols = cols] ui <- fluidPage( headerPanel("shinyStore Example"), sidebarLayout( sidebarPanel = sidebarPanel( initStore("store", "shinyStore-ex1"), actionButton("save", "Save", icon("save")), actionButton("clear", "Clear", icon("stop")) ), mainPanel = mainPanel( fluidRow( textInput(inputId = "text1", label = "A text input", value = ""), DTOutput(outputId = "DT_out") ) ) ) ) server <- function(input, output, session) { rv <- reactiveValues(uiTable = mtcarsDT) mydataTableProxy <- dataTableProxy(outputId = "DT_out") output$DT_out <- renderDT({ datatable(mtcarsDT, selection = "none", editable = list(target = 'cell', disable = list(columns = c(0))) )}) observeEvent(input$DT_out_cell_edit, { # data.frame rownames would need extra handling... if(input$DT_out_cell_edit$col > 0){ rv$uiTable[input$DT_out_cell_edit$row, input$DT_out_cell_edit$col] <- input$DT_out_cell_edit$value } }) observeEvent(input$save, { updateStore(session, name = "text1", input$text1) updateStore(session, name = "uiTable", rv$uiTable) }, ignoreInit = TRUE) observeEvent(input$clear, { # clear current user inputs: updateTextInput(session, inputId = "text1", value = "") replaceData(mydataTableProxy, data = mtcarsDT) # clear tracking table: rv$uiTable <- mtcarsDT # clear shinyStore: updateStore(session, name = "text1", value = "") updateStore(session, name = "uiTable", mtcarsDT) }, ignoreInit = TRUE) observeEvent(input$store$uiTable, { updateTextInput(session, inputId = "text1", value = input$store[["text1"]]) replaceData(mydataTableProxy, data = as.data.frame(input$store$uiTable)) }) } shinyApp(ui, server)