I see some solutions with DT, but this is really kind of overkill and I want the easy ability for the user to add/ delete and move rows around and be able to access these manipulations for other parts of my app.
I would also like to implement this as a reusable module to cut down on code complexity. A simple example with mtcars[1:5,] would be great.
I ended up piecing together a solution using the rhandsontable
library. Here is an example with moveable rows and editable cells connected to tabular output that can easily be fed and interpreted in the R environment:
library(shiny)
library(dplyr)
require(rhandsontable)
#------
#Definition of UI part of ediTable module
ediTable <- function(id, ...) {
ns <- NS(id)
rHandsontableOutput(outputId = ns("hot"), ...)
}
#Server logic for the module
ediTable_server <-
function(id,
rd,
allowRowEdit = TRUE,
allowColumnEdit = FALSE,
manualRowMove = TRUE,
...) {
moduleServer(id,
function(input, output, session) {
output$hot <- renderRHandsontable({
tmp <- isolate(rd())#Gotta isolate it or it'll cause infinite loop
#Necessary to avoid the issue described [here](https://github.com/jrowen/rhandsontable/issues/166)
rownames(tmp) <- NULL
rhandsontable(
tmp,
allowRowEdit = allowRowEdit,
allowColumnEdit = allowColumnEdit,
manualRowMove = manualRowMove,
...
)
})
#Update the reactive values for this user-manipulated data to pass back to main environment
observeEvent(input$hot, {
tmp <- rhandsontable::hot_to_r(input$hot)
rd(tmp)
})
})
}
# Define UI for the main application
ui <- fluidPage(
# Application title
titlePanel("ediTable: editable table widget"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
h3("Motivation:"),
p(
"Sometimes you just want to allow users to edit a table and then save that input data."
),
p(
"This is basically a shallow, more intuitive wrapper for rhandsontable."
)
),
# Show a plot of the generated distribution
mainPanel(
h1("Table 1: a reactive module"),
p("Double click a cell to edit."),
p("Right click to add or remove rows; click and drag to move."),
ediTable(id = "tab"),
h3("Outputting the edited data for Table 1"),
tableOutput("data1"),
h1("Table 2: independently reactive module"),
ediTable(id = "tab2"),
h3("Outputting the edited data for Table 1"),
tableOutput("data2")
)
)
)
# Define server logic for the main application
server <- function(input, output) {
init_data <- head(mtcars)
reactive_data1 <- reactiveVal(init_data)
reactive_data2 <- reactiveVal(init_data)
ediTable_server(id = "tab", rd = reactive_data1)
ediTable_server(id = "tab2", rd = reactive_data2)
observe({
tmp <- reactive_data1()
output$data1 <-
tmp %>% renderTable()
})
observe({
tmp2 <- reactive_data2()
output$data2 <- tmp2 %>% renderTable()
})
}
# Run the application
shinyApp(ui = ui, server = server)