You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
关键修改说明
  1. 新增响应式状态变量:table_2021_exists用来追踪当前选中的表格在2021年是否存在,通过updateCheckboxInput同步到UI层的input.table_2021_exists,供conditionalPanel调用。
  2. 错误捕获与状态更新:在output$Table_2021中用tryCatch包裹逻辑,找不到表格时将table_2021_exists设为0,并返回空表格,避免输出进入错误状态。
  3. 修改conditionalPanel条件:不再依赖output.Table_2021,而是使用input.table_2021_exists的状态控制表格和提示信息的显示,确保切换时状态能正确更新。

内容的提问来源于stack exchange,提问作者Benjamin Fretwurst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:24:10