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.
Related
I have relied on the following Code so that the user can modify the shiny table.
I have a large database, before the user modifies the table I would like him to be able to filter by "material" and then he can make the corresponding modifications, especially the column "stockobj", then I would like to see the filtered table and the main table with the modifications that were made previously.
As you can see in the picture: [App][https://i.stack.imgur.com/2ecpK.png]
My code:
library(DT)
df<- tibble(material=c(12345,12345,12345,12345,12345, 67891,67891,67891,67891,67891),
centro=c("H01", "H02", "H03", "H04","H05","H01", "H02", "H03", "H04","H05" ),
rotaSem= c(0.66,0.55,0.43,0.45, 0.33, 0.34,0.78, 0.31,0.89,0.87),
stockobj=c(1,2,1,1,3,1,1,1,2,1))
shinyApp(
ui = fluidPage(
titlePanel("My app"),
selectInput("mate", "Select material", choices = unique(df$material)),
h3("Edit table"),
DTOutput('x1'),
h3("Main table"),
DTOutput("x2")
),
server = function(input, output, session) {
x = df
categ<-reactive({
x %>% filter(material==input$mate)
})
output$x1 <- renderDT(categ(), selection = 'none', rownames = F, editable = T)
output$x2 <- renderDT({
x
})
proxy = dataTableProxy('x1')
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col + 1 # column index offset by 1
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
})
}
)```
I have been looking for a solution for several days but I have not been able to. The problem is that to modify the table I have to modify the "reactive" and I don't think it is possible. Any ideas?
[1]: https://i.stack.imgur.com/2ecpK.png
Try this
library(DT)
library(dplyr)
df<- data.frame(material=c(12345,12345,12345,12345,12345, 67891,67891,67891,67891,67891),
centro=c("H01", "H02", "H03", "H04","H05","H01", "H02", "H03", "H04","H05" ),
rotaSem= c(0.66,0.55,0.43,0.45, 0.33, 0.34,0.78, 0.31,0.89,0.87),
stockobj=c(1,2,1,1,3,1,1,1,2,1))
shinyApp(
ui = fluidPage(
titlePanel("My app"),
selectInput("mate", "Select material", choices = unique(df$material)),
h3("Edit table"),
DTOutput('x1'),
h3("Main table"),
DTOutput("x2")
),
server = function(input, output, session) {
rv <- reactiveValues(df=df,dfa=NULL,dfb=NULL)
observeEvent(input$mate, {
rv$dfa <- rv$df %>% dplyr::filter(material %in% input$mate)
rv$dfb <- rv$df %>% dplyr::filter(!(material %in% input$mate))
})
observe({
rv$df <- rbind(rv$dfa,rv$dfb)
df1 <- rv$df
newchoices <- unique(df1$material)
selected <- input$mate
updateSelectInput(inputId = 'mate', choices=newchoices, selected=selected)
})
output$x1 <- renderDT(rv$dfa, selection = 'none', rownames = F, editable = T)
output$x2 <- renderDT({ rv$df })
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
i = info$row
j = info$col + 1 # column index offset by 1
v = info$value
rv$dfa[i, j] <<- DT::coerceValue(v, rv$dfa[i, j])
})
}
)
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
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)
})
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
})
}
)
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.