Reputation: 762
I would like to have an editable DT inside a shiny module. When I change a value in the DT, then the table updates and it is empty with the message inside the datatable:
"No matching records found"
My code is as follows:
Modules:
modDtUi <- function(id){ # UI module
ns = NS(id)
DT::dataTableOutput(ns('x1'))
}
modDt <- function(input, output, session, data){ # Server module
x <- data
output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE)
proxy <- dataTableProxy('x1', session = session)
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
print(info)
i = info$row
j = info$col
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE, rownames = FALSE)
})
}
app in flexdashboard:
```{r}
modDtUi("editable")
```
```{r}
callModule(modDt,"editable", data = iris)
```
It works well without modules, but I can't get the same results with shiny modules.
Thanks
Upvotes: 5
Views: 3523
Reputation: 6921
Working from your code, the issue is that the proxy needs the global session (and not the module session). See my other answer for an alternative approach.
You can simply pass the global session
to the module via an argument.
This works:
library(shiny)
library(DT)
modDtUi <- function(id){ # UI module
ns = NS(id)
DT::dataTableOutput(ns('x1'))
}
modDt <- function(input, output, session, data, globalSession){ # Server module
x <- data
output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE)
proxy <- dataTableProxy('x1', session = globalSession)
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
str(info)
print(info)
i = info$row
j = info$col
v = info$value
x[i, j] <<- DT::coerceValue(v, x[i, j])
replaceData(proxy, x, resetPaging = FALSE)
})
}
You now have to add the global session in the module call.
With a shiny app:
ui <- fluidPage(
modDtUi("editable")
)
server <- function(input, output, session) {
callModule(modDt,"editable", data = iris, globalSession = session)
}
shinyApp(ui = ui, server = server)
With a flexdashboard:
```{r}
modDtUi("editable")
```
```{r}
callModule(modDt, "editable", data = iris, globalSession = session)
```
If you want to use your updated table in the rest of your app, simply return reactive(x)
from your module and capture it when you call the module.
editable_iris <- callModule(modDt,"editable", data = iris, globalSession = session)
Upvotes: 2
Reputation: 84519
This works if you remove rownames = FALSE
:
replaceData(proxy, x, resetPaging = FALSE)#, rownames = FALSE)
If you don't want row names, you have to also set rownames = FALSE
in the renderDataTable
:
output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE,
rownames = FALSE)
And then you have to add 1
to info$col
:
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
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)
})
Full code of the Rmd
flexdashboard:
---
title: "Untitled"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
library(flexdashboard)
library(DT)
modDtUi <- function(id){ # UI module
ns = NS(id)
DT::dataTableOutput(ns('x1'))
}
modDt <- function(input, output, session, data){ # Server module
x <- data
output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE,
rownames = FALSE)
proxy <- dataTableProxy('x1', session = session)
observeEvent(input$x1_cell_edit, {
info = input$x1_cell_edit
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)
})
}
```
Column {data-width=650}
-----------------------------------------------------------------------
### Editable table
```{r}
modDtUi("editable")
```
```{r}
callModule(modDt, "editable", data = iris)
```
Upvotes: 4
Reputation: 6921
The following gives me an editable table and captures the edited table in a reactive for further use in the application:
library(shiny)
library(DT)
modDtUi <- function(id){ # UI module
ns = NS(id)
DT::dataTableOutput(ns('x1'))
}
modDt <- function(input, output, session, data){ # Server module
output$x1 <- DT::renderDataTable(data, selection = 'none', editable = TRUE, server = TRUE)
proxy <- dataTableProxy('x1', session = session)
updatedData <- eventReactive(input$x1_cell_edit, {
info = input$x1_cell_edit
if (!is.null(info)) {
str(info)
data[info$row, info$col] <<- DT::coerceValue(info$value,
data[info$row, info$col])
}
data
}, ignoreNULL = FALSE)
return(updatedData)
}
ui <- fluidPage(
modDtUi("editable"),
tags$hr(),
"Proof it works: the table below updates on edit.",
shiny::tableOutput("proof")
)
server <- function(input, output) {
editable_dt <- callModule(modDt,"editable", data = iris)
output$proof <- renderTable({
editable_dt() %>%
summarise_if(is.numeric, mean)
})
}
shinyApp(ui = ui, server = server)
Upvotes: 0