[英]editable DT inside shiny module
I would like to have an editable DT inside a shiny module.我想在闪亮的模块中有一个可编辑的 DT。 When I change a value in the DT, then the table updates and it is empty with the message inside the datatable:
当我更改 DT 中的值时,表会更新,并且数据表中的消息为空:
"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: 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谢谢
This works if you remove rownames = FALSE
:如果您删除
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
:如果你不想要行名,你还必须在
renderDataTable
中设置renderDataTable
rownames = FALSE
:
output$x1 <- DT::renderDataTable(x, selection = 'none', editable = TRUE,
rownames = FALSE)
And then you have to add 1
to info$col
:然后你必须将
1
添加到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: 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)
```
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.您可以简单地通过参数将全局
session
传递给模块。
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.如果您想在应用程序的其余部分使用更新后的表,只需从您的模块返回
reactive(x)
并在调用模块时捕获它。
editable_iris <- callModule(modDt,"editable", data = iris, globalSession = session)
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)
Good Morning早上好
In my code source, i use globalsession but i have the same problem在我的代码源中,我使用 globalsession 但我有同样的问题
library(shiny)
library(DT)
# Data frame df1
# n = 10
# df1 = data.frame(
# month = month.abb[1:n],
# YN = rep(c("[Null]", TRUE), times = c(5, 5)),
# ID = seq_len(n),
# stringsAsFactors = FALSE
# )
# df1[10,3] <- "[Null]"
modDtUi <- function(id){ # UI module
ns = NS(id)
DT::dataTableOutput(ns('x1'))
}
modDt <- function(input, output, session, df1, globalSession){ # Server module
shinyInput = function(FUN, len, id, value, ...) {
if (length(value) == 1)
value <- rep(value, len)
inputs = character(len)
for (i in seq_len(len)) {
inputs[i] = as.character(FUN(paste0(id, i), label = NULL, value = value[i]))
}
inputs
}
# Function for null value
nullValue <- function(selectedColumn, df) {
for (columIndex in selectedColumn) {
df <- subset(df, df[, columIndex] != "[Null]")
}
df
}
# obtain the values of inputs
shinyValue = function(id, len) {
unlist(lapply(seq_len(len), function(i) {
value = input[[paste0(id, i)]]
if (is.null(value))
TRUE
else
value
}))
}
# Data frame with checkbox in the first row
df2 = rbind(ID = shinyInput(
checkboxInput,
ncol(df1),
'ID_',
value = FALSE,
width = '1px'
),
df1)
# Reactive function
loopData = reactive({
df2[1, ] <<-
shinyInput(
checkboxInput,
ncol(df1),
'ID_',
value = shinyValue('ID_', ncol(df1)),
width = '1px'
)
checked <- shinyValue('ID_', ncol(df1))
changed <- which((checked) != 0)
df2 = nullValue(changed, df2)
})
output$x1 = DT::renderDataTable(
isolate(loopData()),
filter = "top",
escape = FALSE,
selection = 'none',
options = list(
dom = 't',
paging = FALSE,
ordering = FALSE,
preDrawCallback = JS(
'function() { Shiny.unbindAll(this.api().table().node()); }'
),
drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
)
)
proxy = dataTableProxy('x1',session=globalSession)
observe({
replaceData(proxy, loopData())
print("yes")
})
}
ui <- fluidPage(
modDtUi("editable")
)
server <- function(input, output, session) {
callModule(modDt,"editable", df1 = iris[,-5], globalSession = session)
}
shinyApp(ui = ui, server = server)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.