根据用户输入更新数据表,包括相应列的更新,而不仅仅是编辑的列
Update datatable based on user input, include update of corresponding columns, not just the one edited
下面的小应用程序生成一个 DT::datatable 包含两列 x,y。 X 开始时是一个具有 rnorm 的随机数。 y 应该是 x 加 1。
该应用程序允许用户编辑 DT::datatable 中的 x 列。我已经构建它以便用户可以修改 x 列,但是,y 列没有按预期更新,它只是保持不变。
闪亮代码:
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
## render DT
render_dt = function(data, editable = 'cell', server = TRUE, ...) {
renderDT(data, selection = 'none', server = server, editable = editable, ...)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
ex_df <- reactive({create_sample_df(x)})
## set to initially be the on open result of ex_df, before any user input
reactivs <- reactiveValues(ex_df = ex_df)
observeEvent(input$ex_df_cell_edit, {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- v
# now update the reactive values object with the newly generated df
reactivs$ex_df <<- reactive({create_sample_df(x)})
})
output$ex_df <- render_dt(data = reactivs$ex_df(),
rownames = FALSE,
list(target = 'cell',
disable = list(columns = c(1))))
}
shinyApp(ui, server)
屏幕截图:
在屏幕上,我要将 x 列的第一行从 -1 编辑为 10。按回车键后,期望的结果是第 1 行的 x 值为 10,y 值为 11。
目前不会发生这种情况,无论如何y都保持不变。此外,第一次尝试编辑 x 列不起作用,只有在第二次尝试后新值才会保留。
问题是如何将反应数据传递给您的自定义 render_dt
。我不完全确定为什么,但无法识别对 reactivs$ex_df
的更改。您在 x 列中看到的更改不是由于更新 ex_df
,而是直接在 table 中进行的更改。因此,我将其改回直接使用 renderDT
。我做了一些额外的更改:
ex_df
本身不是反应性的。它存储在一个 reactiveValues
对象中,其中每个条目本身都是反应性的。
- 分配给
reactiveValues
不需要 <<-
cell_edit
中的编辑值是字符向量
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
ex_df <- create_sample_df(x)
## set to initially be the on open result of ex_df, before any user input
reactivs <- reactiveValues(ex_df = ex_df)
observeEvent(input$ex_df_cell_edit, {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- as.numeric(v)
# now update the reactive values object with the newly generated df
reactivs$ex_df <- create_sample_df(x)
})
output$ex_df <- renderDT({
datatable(reactivs$ex_df,
editable = "cell",
rownames = FALSE,
options = list(target = 'cell',
disable = list(columns = c(1))))
})
}
shinyApp(ui, server)
编辑
这里的解决方案没有 observeEvent
,只有 reactive()
用于 ex_df
。然后你可以将未评估的 reactive
传递给你的 render_dt
函数:
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
## render DT
render_dt = function(data_in, editable = 'cell', server = TRUE, ...) {
renderDT(data_in(), selection = 'none', server = server, editable = editable, ...)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
setup_df <- create_sample_df(x)
ex_df <- eventReactive(input$ex_df_cell_edit, {
# on startup
if (is.null(input$ex_df_cell_edit)) {
setup_df
# for edits
} else {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- as.numeric(v)
create_sample_df(x)
}
},
ignoreNULL = FALSE)
output$ex_df <- render_dt(data_in = ex_df,
rownames = FALSE,
list(target = 'cell',
disable = list(columns = c(1))))
}
shinyApp(ui, server)
下面的小应用程序生成一个 DT::datatable 包含两列 x,y。 X 开始时是一个具有 rnorm 的随机数。 y 应该是 x 加 1。
该应用程序允许用户编辑 DT::datatable 中的 x 列。我已经构建它以便用户可以修改 x 列,但是,y 列没有按预期更新,它只是保持不变。
闪亮代码:
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
## render DT
render_dt = function(data, editable = 'cell', server = TRUE, ...) {
renderDT(data, selection = 'none', server = server, editable = editable, ...)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
ex_df <- reactive({create_sample_df(x)})
## set to initially be the on open result of ex_df, before any user input
reactivs <- reactiveValues(ex_df = ex_df)
observeEvent(input$ex_df_cell_edit, {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- v
# now update the reactive values object with the newly generated df
reactivs$ex_df <<- reactive({create_sample_df(x)})
})
output$ex_df <- render_dt(data = reactivs$ex_df(),
rownames = FALSE,
list(target = 'cell',
disable = list(columns = c(1))))
}
shinyApp(ui, server)
屏幕截图:
在屏幕上,我要将 x 列的第一行从 -1 编辑为 10。按回车键后,期望的结果是第 1 行的 x 值为 10,y 值为 11。
目前不会发生这种情况,无论如何y都保持不变。此外,第一次尝试编辑 x 列不起作用,只有在第二次尝试后新值才会保留。
问题是如何将反应数据传递给您的自定义 render_dt
。我不完全确定为什么,但无法识别对 reactivs$ex_df
的更改。您在 x 列中看到的更改不是由于更新 ex_df
,而是直接在 table 中进行的更改。因此,我将其改回直接使用 renderDT
。我做了一些额外的更改:
ex_df
本身不是反应性的。它存储在一个reactiveValues
对象中,其中每个条目本身都是反应性的。- 分配给
reactiveValues
不需要<<-
cell_edit
中的编辑值是字符向量
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
ex_df <- create_sample_df(x)
## set to initially be the on open result of ex_df, before any user input
reactivs <- reactiveValues(ex_df = ex_df)
observeEvent(input$ex_df_cell_edit, {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- as.numeric(v)
# now update the reactive values object with the newly generated df
reactivs$ex_df <- create_sample_df(x)
})
output$ex_df <- renderDT({
datatable(reactivs$ex_df,
editable = "cell",
rownames = FALSE,
options = list(target = 'cell',
disable = list(columns = c(1))))
})
}
shinyApp(ui, server)
编辑
这里的解决方案没有 observeEvent
,只有 reactive()
用于 ex_df
。然后你可以将未评估的 reactive
传递给你的 render_dt
函数:
library(shiny)
library(tidyverse)
library(shinydashboard)
library(scales)
library(DT)
# define functions
## generate example data
create_sample_df <- function(x) {
data.frame(
x = x %>% unlist
) %>% mutate(y = x + 1)
}
## render DT
render_dt = function(data_in, editable = 'cell', server = TRUE, ...) {
renderDT(data_in(), selection = 'none', server = server, editable = editable, ...)
}
# UI ----
header <- dashboardHeader(title = 'blah')
sidebar <- dashboardSidebar()
body <- dashboardBody(DT::DTOutput('ex_df'))
ui <- dashboardPage(header, sidebar, body)
# Server ----
server <- function(input, output) {
x <- rnorm(10, 0, 2) %>% as.integer %>% as.list
# the df to be displayed as a DT::datatable.
setup_df <- create_sample_df(x)
ex_df <- eventReactive(input$ex_df_cell_edit, {
# on startup
if (is.null(input$ex_df_cell_edit)) {
setup_df
# for edits
} else {
info = input$ex_df_cell_edit
str(info)
i = info$row
j = info$col
v = info$value
# update budgets, which in turn is used to generate data during create_sample_df()
x[[i]] <<- as.numeric(v)
create_sample_df(x)
}
},
ignoreNULL = FALSE)
output$ex_df <- render_dt(data_in = ex_df,
rownames = FALSE,
list(target = 'cell',
disable = list(columns = c(1))))
}
shinyApp(ui, server)