Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add and delete rows of DT Datatable in R Shiny

Tags:

r

dt

shiny

I'm trying to add a "save inputs" feature to my Shiny app where the saved inputs would be saved in a DT data table. If a user clicks an Add button, the inputs would be appended to a data table. A user then can delete a row from this data table by selecting a row and clicking the Delete button. I also need to have this table's values be saved as a global variable so it stays persistent across all sessions.

The example code is shown below. When I close the session, the table (this_table) is correctly updated, however, those changes don't appear realtime during the app. I've tried putting both of these input buttons in an eventReactive function, but this did not work when one of the buttons was selected more than once.

Any ideas?

Global table:

this_table = data.frame(bins = c(30, 50), cb = c(T, F))

Shiny app code:

ui <- fluidPage(

   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30),
         checkboxInput("cb", "T/F"),
         actionButton("add_btn", "Add"),
         actionButton("delete_btn", "Delete")
      ),

      mainPanel(
         DTOutput("shiny_table")
      )
   )
)

server <- function(input, output) {


  observeEvent(input$add_btn, {
    t = rbind(data.frame(bins = input$bins,
                         cb = input$cb), this_table)
    this_table <<- t
  })

  observeEvent(input$delete_btn, {
    t = this_table
    print(nrow(t))
    if (!is.null(input$shiny_table_rows_selected)) {
      t <- t[-as.numeric(input$shiny_table_rows_selected),]
    }
    this_table <<- t
  })

  output$shiny_table <- renderDT({
   datatable(this_table, selection = 'single', options = list(dom = 't'))
  })
}

shinyApp(ui = ui, server = server)
like image 857
Agrosel Avatar asked Sep 20 '18 14:09

Agrosel


1 Answers

You can use reactiveVal to add server side variables that are observable and mutable at the same time. The syntax for those variables is to initialize them as

rV <- reactiveValue("init_value")

and update them with

rV("new_value")

Those variables can be accessed inside reactive contexts (basically like inputs) with

rV()

The syntax is quite unusual for R and might take time to get used to, but it is definitely the recommended way to solve issues like these. You might also want to take a look at reactiveValues for a similar functionality but with a semantic closer to the R class list.

Here is how this technique can be applied to your question

library(shiny)
library(DT)

this_table = data.frame(bins = c(30, 50), cb = c(T, F))

ui <- fluidPage(

  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      checkboxInput("cb", "T/F"),
      actionButton("add_btn", "Add"),
      actionButton("delete_btn", "Delete")
    ),

    mainPanel(
      DTOutput("shiny_table")
    )
  )
)

server <- function(input, output) {

  this_table <- reactiveVal(this_table)

  observeEvent(input$add_btn, {
    t = rbind(data.frame(bins = input$bins,
                         cb = input$cb), this_table())
    this_table(t)
  })

  observeEvent(input$delete_btn, {
    t = this_table()
    print(nrow(t))
    if (!is.null(input$shiny_table_rows_selected)) {
      t <- t[-as.numeric(input$shiny_table_rows_selected),]
    }
    this_table(t)
  })

  output$shiny_table <- renderDT({
   datatable(this_table(), selection = 'single', options = list(dom = 't'))
  })
}

shinyApp(ui = ui, server = server)

Finally, I would like to add that @ Vishesh Shrivastavs recommendation to use the rhandsontable package is also a viable approach, although you will definitely loose some flexibility in doing so.

like image 67
Gregor de Cillia Avatar answered Sep 17 '22 18:09

Gregor de Cillia