1

I am working with the DTedit package and would like to implement two functionalities. I am attaching the code sample from the package author's github. The two things that I would like to implement are:

  • a button that saves the data after any new additions or modifications to the table to a local file. Ideally we can append all new additions (or editions) to an existing csv file. The app will be in rstudio server so we can add this file to the www folder.

  • The second functionality is that the app must pull the data from the csv and show it when the user opens the app, instead of showing an empty table like the one on the code before.

I've been trying a few options and look at a few tutorials on the internet but haven't been able to solve these two questions.

library(shiny)
library(DTedit)

##### Create the Shiny server
server <- function(input, output) {
    mydata <- data.frame(name = character(),
                         email = character(),
                         useR = factor(levels = c('Yes', 'No')),
                         notes = character(),
                         stringsAsFactors = FALSE)

    ##### Callback functions.
    my.insert.callback <- function(data, row) {
        mydata <- rbind(data, mydata)
        return(mydata)
    }

    my.update.callback <- function(data, olddata, row) {
        mydata[row,] <- data[1,]
        return(mydata)
    }

    my.delete.callback <- function(data, row) {
        mydata <- mydata[-row,]
        return(mydata)
    }

    ##### Create the DTedit object
    DTedit::dtedit(input, output,
           name = 'mycontacts',
           thedata = mydata,
           edit.cols = c('name', 'email', 'useR', 'notes'),
           edit.label.cols = c('Name', 'Email Address', 'Are they an R user?', 'Additional notes'),
           input.types = c(notes='textAreaInput'),
           view.cols = c('name', 'email', 'useR'),
           callback.update = my.update.callback,
           callback.insert = my.insert.callback,
           callback.delete = my.delete.callback)
}

##### Create the shiny UI
ui <- fluidPage(
    h3('DTedit Template'),
    uiOutput('mycontacts')
)

##### Start the shiny app
shinyApp(ui = ui, server = server)
Jdv
  • 329
  • 1
  • 10
  • I suggest you consider [shiny persistent storage](https://shiny.rstudio.com/articles/persistent-data-storage.html) or [shiny bookmarking](https://shiny.rstudio.com/articles/bookmarking-state.html). – r2evans Mar 03 '19 at 16:52
  • I see the potential for problems with storage in a local file like that: simultaneous access; access permissions (accidentally sharing/leaking between users); upgrade the app and forget to transfer over the historic CSVs. A sqlite solution (included in the first link above) works better than individual files, though it suggests a `DBI`-centric approach to your data. Bookmarking (second link) handles most of those problems inherently. Over to you, they were just suggestions. – r2evans Mar 03 '19 at 17:47
  • I see. Would a dropbox / google spreadsheet be a better option? The bookmark seems like a good idea but would need the URL to always be the same. I believe bookmarking creates a new address from what I could read – Jdv Mar 03 '19 at 18:14
  • "Best" is purely subjective. I don't know what your existing infrastructure looks like, nor what the full use-case and user-base look like. It it's going to be used by one person a few times over the next two weeks and likely never again, then files within `www/` may suffice. If it's going to be used by multiple people and/or over a longer period, then I might lean towards `sqlite`. If you are in a distributed environment, have more users, and/or long-term maintenance and metrics are factors, then a more robust solution like a SQL server, NoSQL (e.g., redis) server, etc might be best. – r2evans Mar 03 '19 at 18:18
  • 1
    I understand. Thank you. – Jdv Mar 03 '19 at 20:26

1 Answers1

0

I will second the suggestions already in the comments that storage into a database such as sqlite (or even airtable, for which there are R interfaces, if the data is not especially sensitive) is the best solution.

In which case you can use dtedit's callbacks to store the data in the database, as is shown in dtedit's demonstration application in the DTedit github repository.

Answering the specific first point for 'a button that saves the data after any new additions or modifications to the table to a local file. Ideally we can append all new additions (or editions) to an existing CSV file', DT (on which DTedit is based) does have functionality to save the current table into a CSV or Excel file.

I don't think this is the best idea in your case, your application will still be responsible to 're-load' this data on application start and, as others say only one user can write to the CSV/Excel file at a time. In addition, storing a CSV file locally will usually not be done in the package's www/ folder!

Still, if storing a CSV file is the 'quick-hack' solution that suits the application, then it is possible to modify DTedit to pass through the required arguments to DT so that CSV/Excel save buttons are available. I, and others, have modified DTedit to allow arguments to be passed through to DT::datatable, the modified version of DTedit is available on Github. A vignette showing the addition of 'save' buttons is available on RPubs, and is reproduced below.

library(DTedit)

server <- function(input, output) {
  
  Grocery_List_Results <- dtedit(
    input, output,
    name = 'Grocery_List',
    thedata = data.frame(
      Buy = c('Tea', 'Biscuits', 'Apples'),
      Quantity = c(7, 2, 5),
      stringsAsFactors = FALSE
    ),
    datatable.call = function(...)
      {DT::datatable(..., extensions = 'Buttons')},
    datatable.options = list(
      dom = 'Bfrtip',
      buttons = c('copy', 'csv', 'pdf', 'excel')
    )
  )
}

ui <- fluidPage(
    h3('Grocery List'),
    uiOutput('Grocery_List')
)

shinyApp(ui = ui, server = server)

Picture of datatable with Copy/Save buttons

David Fong
  • 506
  • 4
  • 3