dww dww - 12 days ago 9
R Question

In Shiny, update DataTable with new values from user input

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?

Answer

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)
}