How to Save an Editable Datatable – R Shiny App

I am working on a Shiny app that reads data from a CSV and allows a user to filter the data according to text inputs. The table is editable, however any changes made in browser are not saved.

app.R


library(shiny)
library(shinydashboard)
library(dplyr)
library(readr)

# read CSV into data frame
items <- read_csv("example.csv")

# setup UI - text fields to search CSV
ui <- fluidPage(
  img(src="logo.PNG", align='center'),
  fluidRow(
    column(2,
           textInput("id", width="100%", label = "ID"),
    ),
    column(2,
           textInput("name", width="100%", label = "Name"),
    ),
    column(2,
           textInput("biz", width="100%", label = "Business"),
    ),
    column(2,
           textInput("city", width="100%", label = "City"),
    ),
    column(2,
           textInput("country", width="100%", label = "Country"),
    ),
    column(12, align="center", style="padding:5px;",
           actionButton("go", "Search Results", width="95%", align="center")
    ),
    HTML("<hr width=100%>")
  ),
  mainPanel(
    # download button to be rendered in output
    column(9,uiOutput("box")),
    # table to be rendered in output
    DT::dataTableOutput("out")  
  )
)

# Define server logic required to filter CSV table according to text inputs
server <- function(input, output) {
  observeEvent(input$go,{
    # filter display table according to text inputs, then sort alphabetically by name
    displayTable <- items %>%
      filter(grepl(input$id, id, ignore.case = TRUE) | input$id == "") %>%
      filter(grepl(input$name, name, ignore.case = TRUE) | input$name == "") %>%
      filter(grepl(input$biz, biz, ignore.case = TRUE) | input$biz == "") %>%
      filter(grepl(input$city, city, ignore.case = TRUE) | input$city == "") %>%
      filter(grepl(input$country, country, ignore.case = TRUE) | input$country == "") %>%
      # sort table by name
      arrange(tolower(name))
    
    # render the table
    output$out <- DT::renderDataTable(DT::datatable(displayTable, editable=TRUE, options = list(searching=TRUE, iDisplayLength = 100, dom = 'Bfrtip')))
    
    # render the download button
    output$download <- downloadHandler(
      filename = function(){"ItemList.csv"}, 
      content = function(fname){
        write.csv(displayTable, fname, row.names=FALSE)
      }
    )
    
    output[["box"]] <- renderUI(downloadButton('download',"Download table as CSV"))
    
  })
}

# run the application 
shinyApp(ui = ui, server = server)

example.csv

id,name,biz,city,country
1,Jack,Finance,Frankfurt,Germany
2,Jane,Insurance,Minneapolis,USA
3,John,Software,San Francisco,USA

I have tried other solutions I have found here that use a reactive table, but they appear to break functionality with the text inputs and filtering. Would there be a simple way to save any changes made in browser back to the CSV that the app uses to generate the table (example.csv)?

  • The easiest way is to use server = FALSE in the renderDT. If you want to use server = TRUE (the default), you have to use a proxy to update the data at each edit.

    – 

Leave a Comment