【发布时间】:2021-08-31 14:21:21
【问题描述】:
我正在尝试建立一个反馈系统。这是我正在尝试构建的简化示例。我有一个DT:datatable,它会根据选定的输入选项使用反馈列呈现。
反馈通过提交按钮上的observeEvent 提交。所有的 UI 和服务器组件大部分都是我想要的。
library(shiny)
library(shinydashboard)
ui <- ui <- dashboardPage(
header = dashboardHeader(title='Car Recommendations'),
sidebar = dashboardSidebar(
width = 450,
fluidRow(
column(
width = 9,
selectInput(
"cyl", 'Select Cylinder Count:',
choices = c('', sort(unique(mtcars$cyl)))
)
)
)
),
body = dashboardBody(
fluidPage(
fluidRow(
uiOutput('rec_ui')
))
)
)
server <- function(input, output, session) {
mtcarsData <- reactive({
req(input$cyl)
mtcars %>%
filter(cyl == input$cyl) %>%
select(am, wt, hp, mpg)
})
output$rec_ui <- renderUI({
mtcarsData()
mainPanel(
actionButton(
'feedbackButton', 'Submit Feedback', class = 'btn-primary'
),
dataTableOutput(('rec')),
width = 12
)
})
feedbackInputData <- reactive({
mtcars <- mtcarsData()
recsInput <- sapply(1:nrow(mtcars), function(row_id)
input[[paste0('rec', row_id)]]
)
})
observeEvent(input$feedbackButton, {
mtcars <- mtcarsData()
feedbackInput <- feedbackInputData()
recFeedbackDf <- bind_rows(
lapply(1:nrow(mtcars), function(row_id)
list(
shiny_session_token = session$token,
recommendation_type = 'CAR',
input_cyl = input$cyl,
recommended_mpg = mtcars$mpg[row_id],
recommendation_feedback = feedbackInput[row_id],
feedback_timestamp = as.character(Sys.time())
)
)
)
write.table(
recFeedbackDf, 'feedback.csv', row.names = FALSE,
quote = FALSE, col.names = FALSE, sep = '|',
append = TRUE
)
showModal(
modalDialog(
'Successfully submitted', easyClose = TRUE,
footer = NULL, class = 'success'
)
)
})
output$rec <- DT::renderDataTable({
df <- mtcarsData()
feedbackCol <- lapply(1:nrow(df), function(recnum)
as.character(
radioButtons(
paste0('rec', recnum), '',
choices = c('neutral' = 'Neutral', 'good' = 'Good', 'bad' = 'Bad'),
inline = TRUE
)
)
)
feedbackCol <- tibble(Feedback = feedbackCol)
df <- bind_cols(
df,
feedbackCol
)
df %>%
DT::datatable(
extensions = 'FixedColumns',
rownames = FALSE,
escape = FALSE,
class="compact cell-border",
options = list(
pageLength = 10,
lengthChange = FALSE,
scrollX = TRUE,
searching = FALSE,
dom = 't',
ordering = TRUE,
fixedColumns = list(leftColumns = 2),
preDrawCallback = JS(
'function() { Shiny.unbindAll(this.api().table().node()); }'
),
drawCallback = JS(
'function() { Shiny.bindAll(this.api().table().node()); } '
),
autoWidth = TRUE,
columnDefs = list(
list(width = '250px', targets = -1)
)
)
)
})
}
shinyApp(ui = ui, server = server)
但是,在提交后,会发生以下两种情况之一:
- 应用程序崩溃,
write.table中出现以下错误。但是,根本原因是这行代码返回的是NULL值列表,而不是我的反馈输入。
Warning: Error in write.table: unimplemented type 'list' in 'EncodeElement'
feedbackInputData <- reactive({
mtcars <- mtcarsData()
recsInput <- sapply(1:nrow(mtcars), function(row_id)
input[[paste0('rec', row_id)]]
)
})
- 当应用没有崩溃,并且反馈被提交,但新的输入没有生效。只有第一次提交会重复写入 CSV。
知道这个应用程序哪里出了问题吗?
附加信息:我的直觉是,当我从“更少的行”DT 中选择更多的行而不是相反时,会发生崩溃。例如,如果我先选择 8 CYL,它有更多的汽车,然后再选择 4,应用程序在提交时不会崩溃。但反过来,确实如此。顺便说一句 - 无论哪种情况,我的反馈都不会更新。
【问题讨论】:
-
有什么理由让你
renderUI你的dataTableOutput而不是直接把它放入UI?从我看到的renderUI部分对数据没有任何用处,它只是在数据更改时重新呈现表,但它总是会呈现相同的。 -
因为我试图显示反馈按钮和表格,只有当数据存在时,通过反应调用和检查。无论如何,这部分代码结构与我的问题或它不起作用的原因并不真正相关。
-
不是,但它使您的问题过于复杂,因此帮助您变得更加复杂,因为该错误有些混淆。一个好的代表也是最小的。例如,在您的代表中,甚至命名所有
inputs是一项艰巨的任务,因为它们不是在ui和server端创建的。我的意思是,如果你让你的例子更简单,你就有更高的机会获得帮助。 -
我看不到输出表。该应用程序仅显示 selectInput 和反馈按钮。
datatable永远不会被渲染。但是当点击反馈按钮时,我确实得到了同样的错误(总是)。原因是recommendation_feedback列是一个包含NULLs 的列表列。write.table不支持列表列。 -
我知道这一点,并在我的帖子中指出。我试图让它不返回空值列表。此外,这张桌子对我来说很好。不确定是否存在版本问题。