In Shiny, update DataTable with new values from user input
Asked Answered
H

2

7

I'm writing a shiny app that has a table (using DT::renderDataTable) from which users can select a row. But I want the user to also be able to add new row(s) if what they want is not already in the table. I'm using input controls for the user to enter new data, and I have an action button which, if pressed, should create a new row of data in the table from the input values. But pressing the button does not update the table.

A minimal example:

library(shiny)
library(DT)
mydata = data.frame(id=letters[1:5], val=sample(10,5,T))

ui = fluidPage(dataTableOutput("table"),
               textInput('NewID', 'Enter new ID'),
               numericInput('NewVal', 'Enter new val', 1),
               actionButton("goButton", "Update Table"))

server = function(input,output){
  output$table = renderDataTable(mydata)
  update = eventReactive(input$goButton, {
    newrow = data.frame(id = input$NewID, val = input$NewVal)
    mydata = rbind(mydata, newrow)
  })
}

shinyApp(ui,server)

Clearly, this is the wrong way to approach this. I've tried various combinations of wrapping both renderDataTable and the code to update mydata inside renderUI, observe and reactive, but I can't find the right way to do this.

This is my first shiny app, so maybe there is a basic concept that I'm not quite grasping. What is the right way?

Hist answered 25/11, 2016 at 20:27 Comment(4)
Error in force(default) : argument "value" is missing, with no defaultTintype
@Tintype You get this error when paste and run the code? It runs ok for me.Hist
I need to provide the valueparameter for numericInput()Tintype
Thanks @Tintype - I've added that to the example now. Must be a version thing, for some reason it does not throw an error for me when value is missing.Hist
T
9

You can render the result of eventReactive, where you return the updated dataset. Don't forget to use <<- to modify the global dataset as well:

server = function(input,output){
  output$table <- renderDataTable( df())
  df <- eventReactive(input$goButton, {
    if(input$NewID!="" && !is.null(input$NewVal) && input$goButton>0){
      newrow = data.table(id = input$NewID,
                        val = input$NewVal)
      mydata <<- rbind(mydata, newrow)
      }
    mydata
  }, ignoreNULL = FALSE)
}
Tintype answered 25/11, 2016 at 21:32 Comment(2)
Excellent! That is very nearly there. The only small issue is that it adds a new row with a blank id before the button has been pressed. Do you know how to suppress that?Hist
I added a check input$goButton>0 meaning the button has been clickedTintype
A
2

You should use replaceData() function from package DT. Example:

...
  dataTableOutput("OPreview"),
  actionButton("BRefresh","Refresh"),
...

in server part(assuming ds is a dataset to show):

output$OPreview<-renderDataTable({ ds })

onclick("BRefresh",{
  proxy=dataTableProxy("OPreview")
  replaceData(proxy,ds)
})

Albertinealbertite answered 16/2, 2019 at 16:41 Comment(1)
This does not work.Hist

© 2022 - 2024 — McMap. All rights reserved.