Using reactiveValues
to get the DT
to update on change and I used validate to make sure that numbers are correctly provided, clean
is where the magic happens, it checks if the column is a factor
if so check if the value is a level then if not add it.
library(DT)
iris2 = iris %>% group_by(Species) %>% filter(Petal.Length==max(Petal.Length))
# get the classes of the columns
types <- sapply(iris2, class)
ui <- fluidPage(
fluidRow(column(12, DTOutput("table"))
)
)
types <- sapply(iris2, class)
server <- function(input, output, session) {
proxy <- DT::dataTableProxy('table')
RV <- reactiveValues(data = iris2)
output$table = DT::renderDT({
RV$data
}, filter = "top", editable=T)
observeEvent(input$table_cell_edit, {
validate(
need(check_coercibility(input$table_cell_edit$value, types[input$table_cell_edit$col]), "Please enter valid data")
)
RV$data <- clean(RV$data, input$table_cell_edit$value, input$table_cell_edit$row, input$table_cell_edit$col)
}, ignoreInit = TRUE)
}
check_coercibility <- function(x, type){
if(type == "numeric") {
suppressWarnings(!is.na(as.numeric(x)))
} else T
}
clean <- function(df, x, nrow, ncol, type=types[[ncol]]){
col <- df[[ncol]]
df[nrow, ncol] <- if(type=="factor"){
if(! x %in% levels(col)) df[[ncol]] <- factor( col, levels=c(levels(col), x))
x
} else if(type=="numeric"){
as.numeric(x)
} else if(type=="logical"){
as.logical(x)
} else x
df
}
shinyApp(ui, server)