如何在提交后使用基于 Reactive 的过滤可见数据更新 Shiny Datatable?
How to update Shiny Datatable after Submit with Filtered Visible Data based on Reactive?
这是我向 SO 提出的第一个问题,我会尽量简短明了。
我正在修改一个基本的 Shiny CRUD 版本,该版本由 Dean Attali(感谢您)提供,用于研究目的。为此,我生成了一个玩具 MRE(见下文),展示了我试图实现的主要行为。
- 用户筛选显示基于反应的数据(refreshData() based on input$item_used)
- 用户可以添加或删除新条目(saveData()、deleteData())
- 用户可以单击行并通过 DT::dataTableOutput.
动态查看反应性变化
我的问题如下:如果用户添加了一个新条目,并且在下拉列表中的两个选项之一上过滤了可见的 DT 数据 selection,那么 活动设备标识符视图不更新。假设用户向 'B' 项添加了一个新条目,所有且只有 'B' 项在 table 中可见(通过下拉列表过滤)——以便查看新条目,她必须 select 'A' 项,然后 select 'B' 项,到 'refresh' 中的 table以查看新条目。
我知道这里有一个基于反应性的简单解决方案,但我似乎无法识别它。非常感谢您的集体帮助!
library(shiny)
library(shinyjs)
# Define the fields we want to save from the form
fields <- c("name", "item_used", "notes")
data <- data.frame(name = c("Luthien","Aredhel","Beren","Turin"),
item_used = c("A","B","A","B"),
notes = c("fixed","not broken","almost fixed", "beyond repair"),
stringsAsFactors = FALSE)
# Shiny app with 3 fields that the user can submit data for
shinyApp(
ui = fluidPage(sidebarLayout(
sidebarPanel(width = 3,
selectInput("select_used", "Item Used?", choices = c("", "A","B")),
tags$hr(),
lapply(1:length(fields), function(x) textInput(fields[x], fields[x])),
actionButton("submit", "Submit"),
actionButton("delete", "Delete")
),
mainPanel(DT::dataTableOutput("maindata", width = 300),
tags$hr()
))),
server = function(input, output, session) {
# Whenever a field is filled, aggregate all form data
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
# When the Submit button is clicked, save the form data
observeEvent(input$submit, {
saveData(formData())
})
# Show the previous responses
# (update with current response when Submit is clicked)
output$maindata <- DT::renderDataTable({
input$delete
input$submit
refreshData()
})
observeEvent(input$maindata_rows_selected, {
dat <- refreshData()[input$maindata_rows_selected,]
for(i in 1:length(dat)){
updateTextInput(session, fields[i], value = unname(dat[i]))
}
})
observeEvent(input$delete,{
deleteData()
})
deleteData <- function(){
delrow <- row.names(refreshData()[input$maindata_rows_selected,])
data <- loadData()[-c(as.numeric(delrow)),]
data <<- data
}
loadData <- function(){
data <- data
return(data)
}
saveData <- function(data) {
data <- rbind(loadData(), formData())
data <<- data
}
refreshData <- reactive({
data <- loadData()
if(input$select_used == ""){
data
} else {
data[data$item_used == input$select_used, ]
}
})
}
)
我已经回答了我自己的问题,我将 post 放在这里以防其他人发现它有用。解决方案非常简单。
与其将 "refreshed data" 定义为反应式,不如将其定义为函数。所以...
refreshData <- reactive({...})
...应该...
refreshData <- function(){...}
无需对原始代码进行其他更改。通过将 refreshData 更改为函数,可以插入新数据(通过输入字段),同时保留基于用户输入的过滤视图(在 DT 中)。
这是我向 SO 提出的第一个问题,我会尽量简短明了。
我正在修改一个基本的 Shiny CRUD 版本,该版本由 Dean Attali(感谢您)提供,用于研究目的。为此,我生成了一个玩具 MRE(见下文),展示了我试图实现的主要行为。
- 用户筛选显示基于反应的数据(refreshData() based on input$item_used)
- 用户可以添加或删除新条目(saveData()、deleteData())
- 用户可以单击行并通过 DT::dataTableOutput. 动态查看反应性变化
我的问题如下:如果用户添加了一个新条目,并且在下拉列表中的两个选项之一上过滤了可见的 DT 数据 selection,那么 活动设备标识符视图不更新。假设用户向 'B' 项添加了一个新条目,所有且只有 'B' 项在 table 中可见(通过下拉列表过滤)——以便查看新条目,她必须 select 'A' 项,然后 select 'B' 项,到 'refresh' 中的 table以查看新条目。
我知道这里有一个基于反应性的简单解决方案,但我似乎无法识别它。非常感谢您的集体帮助!
library(shiny)
library(shinyjs)
# Define the fields we want to save from the form
fields <- c("name", "item_used", "notes")
data <- data.frame(name = c("Luthien","Aredhel","Beren","Turin"),
item_used = c("A","B","A","B"),
notes = c("fixed","not broken","almost fixed", "beyond repair"),
stringsAsFactors = FALSE)
# Shiny app with 3 fields that the user can submit data for
shinyApp(
ui = fluidPage(sidebarLayout(
sidebarPanel(width = 3,
selectInput("select_used", "Item Used?", choices = c("", "A","B")),
tags$hr(),
lapply(1:length(fields), function(x) textInput(fields[x], fields[x])),
actionButton("submit", "Submit"),
actionButton("delete", "Delete")
),
mainPanel(DT::dataTableOutput("maindata", width = 300),
tags$hr()
))),
server = function(input, output, session) {
# Whenever a field is filled, aggregate all form data
formData <- reactive({
data <- sapply(fields, function(x) input[[x]])
data
})
# When the Submit button is clicked, save the form data
observeEvent(input$submit, {
saveData(formData())
})
# Show the previous responses
# (update with current response when Submit is clicked)
output$maindata <- DT::renderDataTable({
input$delete
input$submit
refreshData()
})
observeEvent(input$maindata_rows_selected, {
dat <- refreshData()[input$maindata_rows_selected,]
for(i in 1:length(dat)){
updateTextInput(session, fields[i], value = unname(dat[i]))
}
})
observeEvent(input$delete,{
deleteData()
})
deleteData <- function(){
delrow <- row.names(refreshData()[input$maindata_rows_selected,])
data <- loadData()[-c(as.numeric(delrow)),]
data <<- data
}
loadData <- function(){
data <- data
return(data)
}
saveData <- function(data) {
data <- rbind(loadData(), formData())
data <<- data
}
refreshData <- reactive({
data <- loadData()
if(input$select_used == ""){
data
} else {
data[data$item_used == input$select_used, ]
}
})
}
)
我已经回答了我自己的问题,我将 post 放在这里以防其他人发现它有用。解决方案非常简单。
与其将 "refreshed data" 定义为反应式,不如将其定义为函数。所以...
refreshData <- reactive({...})
...应该...
refreshData <- function(){...}
无需对原始代码进行其他更改。通过将 refreshData 更改为函数,可以插入新数据(通过输入字段),同时保留基于用户输入的过滤视图(在 DT 中)。