Shiny conditionalPanel更新异常求助:表格存在性判断失效
问题分析
你的问题核心在于:当切换到2021年不存在的表格(Table_2)时,output$Table_2021会因get()找不到对象而抛出错误,此时Shiny会将该输出标记为错误状态。即便之后切回存在的Table_1_2021,这个错误状态不会自动清除,导致conditionalPanel的output.Table_2021判断逻辑失效,错误提示持续显示,表格无法正常渲染。
解决方案
通过以下三步修复:
- 在Server端创建响应式状态变量,专门追踪当前选中的表格是否存在于2021年
- 用
tryCatch捕获renderDataTable中的错误,避免输出进入错误状态,同时更新响应式变量 - 修改
conditionalPanel的判断条件,基于这个响应式变量控制显示逻辑
修改后的完整代码
library(shiny) library(DT) Table_1 <- data.frame(Antworten = "mean", Total = 3, US = 3.5, FR = 4, IT = 2, male = 0, female = 1) Table_2 <- data.frame(Antworten = "mean", Total = 2, US = 2.5, FR = 3, IT = 1, male = 1, female = 2) Table_1_2021 <- data.frame(Antworten = "mean", Total = 4, US = 4.5, FR = 5, IT = 3, male = 3, female = 10) # 2021年缺少Table_2 tabnames <- c("Table_1", "Table_2") # Columns kopfvariablen <- c("region", "sex") default_vars <- c("region") # Shiny ---- ui <- fluidPage( titlePanel(title=div("Tables")), sidebarLayout( sidebarPanel(width = 2, tags$style(".well {background-color: #ffffff; border-color: #ffffff}"), a(br(), br(), br(), br()), checkboxInput( inputId = "year_2022", label = "Tabs: 2022", value = TRUE), checkboxInput( inputId = "year_2021", label = "Tabs: 2021", value = TRUE) ), mainPanel( align = "center", actionButton("prevBin", "<", class="btn btn-success"), actionButton("nextBin", ">", class="btn btn-success"), selectInput( inputId = "dataset", label = "", choices = tabnames, width = "60%"), conditionalPanel( condition = "input.year_2022 == 1 ", DT::dataTableOutput("Table_2022")), # 改用自定义响应式变量判断 conditionalPanel(inline = T, condition = "input.year_2021 == 1 && input.table_2021_exists == 1", DT::dataTableOutput('Table_2021')), conditionalPanel(inline = T, condition = "input.year_2021 == 1 && input.table_2021_exists == 0", h4("[This Question was not asked in 2021.]", align = "left", style = "color:grey")) ) )) server = function(input, output, session) { # 创建响应式变量,标记当前表格在2021年是否存在 table_2021_exists <- reactiveVal(1) # 同步到input对象,供conditionalPanel调用 observe({ updateCheckboxInput(session, "table_2021_exists", value = table_2021_exists()) }) # "next" and "previous" buttons observeEvent(input$prevBin, { current <- which(tabnames == input$dataset) if(current > 1){ updateSelectInput(session, "dataset", choices = as.list(tabnames), selected = tabnames[current - 1]) } }) observeEvent(input$nextBin, { current <- which(tabnames == input$dataset) if(current < length(tabnames)){ updateSelectInput(session, "dataset", choices = as.list(tabnames), selected = tabnames[current + 1]) } }) # Tables 2022 ----- output$Table_2022 <- DT::renderDataTable({ data <- get(input$dataset) data_fin <- data[,1:7] subheader <- c("US", "FR", "IT", "male", "female") topheader_txt <- "tr(th(rowspan = 2, 'Values'), th(rowspan = 2, 'Total') , th(class = 'dt-center', colspan = 3, 'region'), th(class = 'dt-center', colspan = 2, 'sex'))" topheader <- parse(text=topheader_txt) sketch = htmltools::withTags(table( class = 'display', thead( eval(topheader), tr(lapply(subheader, th)) ) )) DT::datatable(data_fin, container = sketch, rownames = F) }) # Tables 2021 ----- output$Table_2021 <- DT::renderDataTable({ table_name <- paste0(input$dataset, "_2021") # 用tryCatch捕获错误,更新状态变量 tryCatch({ data <- get(table_name) table_2021_exists(1) data_fin <- data[,1:7] subheader <- c("US", "FR", "IT", "male", "female") topheader_txt <- "tr(th(rowspan = 2, 'Values'), th(rowspan = 2, 'Total') , th(class = 'dt-center', colspan = 3, 'region'), th(class = 'dt-center', colspan = 2, 'sex'))" topheader <- parse(text=topheader_txt) sketch = htmltools::withTags(table( class = 'display', thead( eval(topheader), tr(lapply(subheader, th)) ) )) js <- c( "function(settings){", " var datatable = settings.oInstance.api();", " var table = datatable.table().node();", " var caption = '2021'", " $(table).append('<caption style=\"caption-side: top-right; text-align: center; margin: 8px 0; font-size: 2em\">' + caption + '</caption>');", "}" ) DT::datatable(data_fin, container = sketch, rownames = F, caption = tags$caption( style="caption-side: bottom; text-align: left; margin: 8px 0;" ), extensions = c('Buttons'), options = list(initComplete = JS(js)) ) }, error = function(e) { table_2021_exists(0) # 返回空表格,避免输出进入错误状态 DT::datatable(data.frame(), rownames = F) }) }) } shinyApp(ui, server)
关键修改说明
- 新增响应式状态变量:
table_2021_exists用来追踪当前选中的表格在2021年是否存在,通过updateCheckboxInput同步到UI层的input.table_2021_exists,供conditionalPanel调用。 - 错误捕获与状态更新:在
output$Table_2021中用tryCatch包裹逻辑,找不到表格时将table_2021_exists设为0,并返回空表格,避免输出进入错误状态。 - 修改conditionalPanel条件:不再依赖
output.Table_2021,而是使用input.table_2021_exists的状态控制表格和提示信息的显示,确保切换时状态能正确更新。
内容的提问来源于stack exchange,提问作者Benjamin Fretwurst
相关产品推荐
相关产品推荐

