How to add rows to DT package while saving the edits made - r

I am trying to develop a shiny app that will allow users to add, delete and save edits to a DT table with the editable settings enabled. However for some reason I am not being able to add a row. Anybody has any clues as to why this is happening?
I am using the iris dataset as an example. (saveRDS(iris,"iris.rds"))
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1'),
actionButton("save", "Save Table"),
actionButton("add_btn","Add Button")
),
server = function(input, output, session) {
x <- readRDS("iris.rds")
output$x1 = renderDT(x, selection = 'none', editable = TRUE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE) })
observeEvent(input$add_btn,
{newrow <- setNames(data.frame(matrix(ncol = ncol(x), nrow = 1)),
colnames(x))
x<<-rbind(x,newrow)})
observeEvent(input$save,
{saveRDS(x, "iris.rds")
})
}
)

You were using values$data an unknown data.frame instead of using x, and u weren't updating the DT output using the replaceData function:
observeEvent(input$add_btn,
{ newrow <- setNames(data.frame(matrix(ncol = ncol(x), nrow = 1)),
colnames(x))
x<<-rbind(x,newrow)
replaceData(proxy, x, resetPaging = F)
})

Related

How to trigger edit on single click in R Shiny DT datatable

I have a Shiny app with an editable DT table. Everything is working perfectly on desktop: I double click on a cell, edit the value, the value is processed in the background, and the whole table is updated appropriately.
However, on Chrome for Android double-click doesn't seem to be an option, so I can't edit the cells in my table.
After much searching for solutions, I tried to add a callback to trigger a doubleclick on a single click, but it doesn't have any effect. I give a minimal example below.
library(shiny)
library(DT)
ui <- fluidPage( mainPanel( DTOutput("table") ) )
server <- function(input, output, session) {
NumDays <- 14
DayNum <- seq_len(NumDays)
DF <- data.frame(Day=DayNum, Week=((DayNum-1) %/% 7 + 1), Steps=rep(0, NumDays), row.names=NULL)
proxy <- dataTableProxy('table')
js <- "table.on('click', 'tr', function() {
table.cell(this).trigger('dblclick.dt');
});"
output$table <- renderDT(datatable(DF, rownames = FALSE, selection = list(mode = 'none'), editable = list(target='cell'), options = list(scrollY = 600, searching = FALSE, paging=FALSE, ordering=FALSE, info=FALSE), callback = JS(js)))
proxy <- dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info <- input$table_cell_edit
i <- info$row; j <- info$col+1; v <- info$value
currentvalue <- abs(as.numeric(v))
DF[i, j] <<- currentvalue + 10
replaceData(proxy, DF, rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
I just tweaked your example with a bit jquery and got it to work - also note I changed 'tr' to 'td':
library(shiny)
library(DT)
ui <- fluidPage( mainPanel( DTOutput("table") ) )
server <- function(input, output, session) {
NumDays <- 14
DayNum <- seq_len(NumDays)
DF <- data.frame(Day=DayNum, Week=((DayNum-1) %/% 7 + 1), Steps=rep(0, NumDays), row.names=NULL)
proxy <- dataTableProxy('table')
js <- "table.on('click', 'td', function() {
$(this).dblclick();
});"
output$table <- renderDT(datatable(DF, rownames = FALSE, selection = list(mode = 'none'), editable = list(target='cell'), options = list(scrollY = 600, searching = FALSE, paging=FALSE, ordering=FALSE, info=FALSE), callback = JS(js)))
proxy <- dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info <- input$table_cell_edit
i <- info$row; j <- info$col+1; v <- info$value
currentvalue <- abs(as.numeric(v))
DF[i, j] <<- currentvalue + 10
replaceData(proxy, DF, rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
Hope this helps

R Shiny Datatable - Editing values, impacting other columns, and retaining paging

I'm trying to allow the user to edit DT values, and based on those edits, run calculations on other columns. That works great on page one, but editing values on subsequent pages resets the paging back to the first page - a nightmare from a UX perspective.
Sample App demonstrating problem.
Try editing a vs value on Page 2 to see what happens...
library(shiny)
library(DT)
library(dplyr)
shinyApp(
ui = fluidPage(
DTOutput('table')
),
server = function(input, output, session) {
x = reactiveValues(df = mtcars %>% select(vs,am))
output$table = renderDT(x$df, editable = TRUE)
proxy = dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info = input$table_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
x$df[i,which(colnames(x$df)=='am')] <- x$df[[i, j]]*2
replaceData(proxy, x$df, resetPaging = FALSE) # important I have tried with and without this line no impact on page resetting
})
}
)
Based on this post, I tried removing the reactivity, but it won't accept multiple edits. Try making two edits to vs on the first page to see what happens...
library(shiny)
library(DT)
library(dplyr)
shinyApp(
ui = fluidPage(
DTOutput('table')
),
server = function(input, output, session) {
df <- mtcars %>% select(vs,am)
output$table = renderDT(df, editable = TRUE)
proxy = dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info = input$table_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
df[i, j] <- isolate(DT::coerceValue(v, df[i, j]))
df[i,which(colnames(df)=='am')] <- df[[i, j]]*2
replaceData(proxy, df, resetPaging = FALSE)
})
}
)
Any pointers would be GREATLY appreciated!
SOLVED...
Thanks to this post...
R Shiny - multi-page editable DataTable jumps to row #1 after an edit
Solution is to isolate the reactive df in the renderDT() function like this...
library(shiny)
library(DT)
library(dplyr)
shinyApp(
ui = fluidPage(
DTOutput('table')
),
server = function(input, output, session) {
x = reactiveValues(df = mtcars %>% select(vs,am))
output$table = renderDT(isolate(x$df), editable = TRUE)
proxy = dataTableProxy('table')
observeEvent(input$table_cell_edit, {
info = input$table_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
x$df[i,which(colnames(x$df)=='am')] <- x$df[[i, j]]*2
replaceData(proxy, x$df, resetPaging = FALSE) # important I have tried with and without this line no impact on page resetting
})
}
)

How to solve 'coerceValue'-error when using a data-frame?

shinyApp(
ui = fluidPage(
DTOutput('x1')
),
server = function(input, output, session) {
x = iris
output$x1 = renderDT(x, selection = 'none', editable = list(target = 'row', disable = list(columns=c(1,3,4))))
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE) # important
})
}
)
I obtain the following warnings:
Warning in DT::coerceValue(v, x[i, j]) :
The data type is not supported: data.frame
Warning: Error in [[: attempt to select less than one element in integerOneIndex
How do I make sure coerceValue is editing and saving my new input?
Quick question: you seem to be using most of the example from here but not all. Is there a reason for that? You could use the code there, as below, which is simpler:
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1')
),
server = function(input, output, session) {
x = iris
output$x1 = renderDT(x, selection = 'none', editable = list(target = 'cell', disable = list(columns=c(1,3,4))))
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
x <<- editData(x, info)
replaceData(proxy, x, resetPaging = FALSE) # important
})
}
)
PS: target = "cell" as mentioned by Stéphane Laurent.

R Shiny DT - edit values in table with reactive

Is it possible to update a reactive data source by editing the DT::DataTable? Below code is based on this code with change that x is made reactive. The problem starts when trying to change x in observeEvent.
The purpose of having x reactive is that I intend to source it from an external database, then have edits to the DT::DataTable write back to the database so that it stays in sync with what the user sees (I'm fine with doing that - it is not part of the question).
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1')
),
server = function(input, output, session) {
x = reactive({
df <- iris
df$Date = Sys.time() + seq_len(nrow(df))
df
})
output$x1 = renderDT(x(), selection = 'none', editable = TRUE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# problem starts here
x()[i, j] <<- isolate(DT::coerceValue(v, x()[i, j]))
replaceData(proxy, x(), resetPaging = FALSE) # important
})
}
)
I am not sure if I understand you correctly, but maybe this solution might help you a bit. I changed your reactive into a reactiveValues object and I removed the replaceData line.
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1'),
verbatimTextOutput("print")
),
server = function(input, output, session) {
x = reactiveValues(df = NULL)
observe({
df <- iris
df$Date = Sys.time() + seq_len(nrow(df))
x$df <- df
})
output$x1 = renderDT(x$df, selection = 'none', editable = TRUE)
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# problem starts here
x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
})
output$print <- renderPrint({
x$df
})
}
)
If you don't show the row names in your DT then you should add 1 to info$col to get the correct column i.e., j = info$col + 1.

Editable Data Table in R

I am trying to edit data table and update the records post row editing on click of action button "Update Table". How to retrive/display new Data table records reactively post modifying fields in existing Data table record?
library(shiny)
library(shinyjs)
library(DT)
library(data.table)
mydata = data.frame(id=letters[1:5], val=sample(10,5,T))
lengthofData <- nrow(mydata)
mydata[["Constraint Type"]] <- c(">")
))
mydata[["Constraint Value"]] <- c(1)
ui = fluidPage(dataTableOutput("table"),
actionButton("goButton", "Update Table"),
dataTableOutput("newtable"))
server = function(input,output){
x <- mydata
output$table <- renderDataTable( x,server = FALSE,
escape = FALSE,
selection = 'none')
proxy = dataTableProxy('table')
xNew<-reactiveValues()
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col + 1
v = info$value
x[i, j] <<- DT:::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
xNew<<-x
})
observeEvent(input$goButton,{
output$newtable <- renderDataTable( xNew(),server = FALSE,
escape = FALSE,
selection = 'none')
})
}
shinyApp(ui,server)

Resources