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

手动清空dateRangeInput()触发Error in if报错问题排查

问题排查与修复

问题描述

我之前有两个需求:

  • 管理空的dateRangeInput()
  • 处理起始日期晚于结束日期的错误

我把两个需求的解决方案整合到了同一段Shiny代码中,代码大部分场景运行正常,但手动完全清空日期范围输入框(任一日期框为空)时,会触发报错:Error in if: missing value, TRUE/FALSE is required。

问题原因

报错核心是代码未妥善处理dateRangeInput为空(包含NA)的情况:

  1. 在observeEvent(input$dates)中,输入框为空时start或end会被解析为NA,执行if (start > end)时,NA无法被判定为TRUE/FALSE,直接触发报错。
  2. 另一个observe块中,!any(is.na(input$dates))的判断逻辑未先确认input$dates是否存在,且当输入包含NA时,后续日期处理逻辑仍会执行,导致无效计算。

修复后的代码

library(shiny)
library(shinydashboard)
library(rhandsontable)
library(data.table)
library(dplyr)
library(lubridate)
library(shinyalert)

DF1 <- data.table(
  "date" = as.character(NA),
  "docname" = as.character(NA),
  stringsAsFactors = FALSE)

DF2 <- data.table(
  "date" = as.character(NA),
  "docname" = as.character(NA),
  stringsAsFactors = FALSE)

ui <- fluidPage(
  dashboardPage(
    dashboardHeader(),
    dashboardSidebar(
      sidebarMenu(
        menuItem("Tab1", tabName = "table1")
      )
    ),
    
    dashboardBody(
      tabItems(
        tabItem(tabName = "table1",
                fluidRow(
                  column(
                    width = 8,
                    label=NULL,
                    rHandsontableOutput("table1Item1")
                  ),
                  column(
                    width = 6,
                    label=NULL,
                    selectInput("choices", label=NULL,
                                choices = c("choice 1", "choice 2")),
                    uiOutput("nested_ui1")
                  ),
                  column(
                    width = 8,
                    label=NULL,
                    rHandsontableOutput("table1Item2")
                  )
                )
        )
      )
    )
  )
)

server = function(input, output, session) {
  
  r <- reactiveValues(
    start = ymd(Sys.Date()),
    end = ymd(Sys.Date())
  )
  
  data <- reactiveValues()
  
  observe({
    data$df1 <- as.data.table(DF1)
    data$df2 <- as.data.table(DF2)
  })
  
  observe({
    if (!is.null(input$table1Item1)) {
      data$df1 <- hot_to_r(input$table1Item1)
    }
  })
  
  observe({
    if(!is.null(input$table1Item2)) {
      data$df2 <- hot_to_r(input$table1Item2)
    }
  })
  
  observeEvent(input$dates, {
    # 空日期直接跳过处理,避免NA引发逻辑错误
    if (any(is.na(input$dates))) {
      return()
    }
    start <- ymd(input$dates[[1]])
    end <- ymd(input$dates[[2]])
    
    if (start > end) {
      shinyalert("错误:结束日期早于起始日期", type = "error")
      updateDateRangeInput(
        session, 
        "dates", 
        start = r$start,
        end = r$end
      )
    } else {
      r$start <- input$dates[[1]]
      r$end <- input$dates[[2]]
    }
  }, ignoreInit = TRUE)
  
  observe({ 
    if (!is.null(input$table1Item1)) {
      data$df1 <- hot_to_r(input$table1Item1) 
      
      if (input$choices == "choice 1") {
        # 先检查日期输入是否有效
        if (!is.null(input$dates) && !any(is.na(input$dates))) {
          from <- as.Date(input$dates[1L])
          to <- as.Date(input$dates[2L])
          if (from > to) to = from
          selectdates1_1 <- seq.Date(from=from, to=to, by = "day")
          data$df2 <- data$df1[as.Date(data$df1$date) %in% selectdates1_1, ]
        } else {
          # 日期为空时返回全部数据
          selectdates1_2 <- unique(data$df1$date)
          data$df2 <- data$df1[data$df1$date %in% selectdates1_2, ]
        }
      } else if (input$choices == "choice 2") {
        if (!is.null(input$text) && input$text != "") {
          data$df2 <- data$df1[data$df1$docname == input$text, ]
        } else {
          # 文本为空时返回全部数据
          selectdates1_2 <- unique(data$df1$date)
          data$df2 <- data$df1[data$df1$date %in% selectdates1_2, ]
        }
      } else {
        selectdates1_2 <- unique(data$df1$date)
        data$df2 <- data$df1[data$df1$date %in% selectdates1_2, ]
      }
    }
  })  
  
  output$table1Item1 <- renderRHandsontable({
    rhandsontable(data$df1, stretchH = "all", height = 100,) |>
      hot_col(1, dateFormat = "YYYY-MM-DD", type = "date")
  })
  
  output$nested_ui1 <- renderUI({
    fluidRow(
      if (input$choices == "choice 1") {
        dateRangeInput("dates", "选择日期:", format="yyyy-mm-dd",
                       start = Sys.Date(), end = Sys.Date(), separator = "-")
      } else if (input$choices == "choice 2") {
        textInput("text", "选择文档名称:")
      })
  })
  
  output$table1Item2 <- renderRHandsontable({
    rhandsontable(data$df2, stretchH = "all") |>
      hot_col(1, dateFormat = "YYYY-MM-DD", type = "date")
  })
  
}

shinyApp(ui, server)

关键修改点

  1. 在observeEvent(input$dates)中新增空日期判断,直接跳过无效输入的处理逻辑,避免NA引发的判断错误。
  2. 重构observe块的条件判断顺序:先确认选项类型,再判断输入是否有效,为空时统一返回全部数据,避免无效计算。
  3. 为choice 2的文本输入补充空值处理,保持功能行为一致性。

内容的提问来源于stack exchange,提问作者firuz.safaev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:02:04