My previous question 1 was about managing empty dateRangeInput()
. My previous question 2 was about error-handling when an initial date is posterior to an end date.
I have integrated the solutions to both questions into one code and it is running well. But when a daterange input is fully erased by hand (i.e. when any of the date boxes is made empty) it is giving an Error in if: missing value, TRUE/FALSE is required
.
Can someone show me what is wrong or missing in the code below?
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, {
start <- ymd(input$dates[[1]])
end <- ymd(input$dates[[2]])
if (start > end) {
shinyalert("Error: end date > initial date", 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 (!any(is.na(input$dates)) && input$choices == "choice 1") {
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 if (!is.null(input$text) && input$choices == "choice 2") {
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, ]
}
}
})
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", "Choose date:", format="yyyy-mm-dd",
start = Sys.Date(), end = Sys.Date(), separator = "-")
} else if (input$choices == "choice 2") {
textInput("text", "Choose docname:")
})
})
output$table1Item2 <- renderRHandsontable({
rhandsontable(data$df2, stretchH = "all") |>
hot_col(1, dateFormat = "YYYY-MM-DD", type = "date")
})
}
shinyApp(ui, server)
The issue is that in your observeEvent(input$dates, ...
you have the if
condition if (start > end)
and this can't handle things if start
or end
is NA
(what is the case if the user clears the DateRangeInput
).
You could circumvent this by using a tryCatch
which in case of an error resets the DateRangeInput
to Sys.Date()
and throws a shinyalert
that the DateRangeInput
can't be empty and therefore was resetted, see the code below.
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, {
start <- ymd(input$dates[[1]])
end <- ymd(input$dates[[2]])
tryCatch({
if (start > end) {
shinyalert("Error: end date > initial date", type = "error")
updateDateRangeInput(session,
"dates",
start = r$start,
end = r$end)
} else {
r$start <- input$dates[[1]]
r$end <- input$dates[[2]]
}
}, error = function(e) {
updateDateRangeInput(session,
"dates",
start = ymd(Sys.Date()),
end = ymd(Sys.Date()))
shinyalert("DateRangeInput can't be empty! Resetting to Sys.Date().",
type = "error")
})
}, ignoreInit = TRUE)
observe({ if (!is.null(input$table1Item1)) {
data$df1 <- hot_to_r(input$table1Item1)
if (!any(is.na(input$dates)) && input$choices == "choice 1") {
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 if (!is.null(input$text) && input$choices == "choice 2") {
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, ]
}
}
})
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", "Choose date:", format="yyyy-mm-dd",
start = Sys.Date(), end = Sys.Date(), separator = "-")
} else if (input$choices == "choice 2") {
textInput("text", "Choose docname:")
})
})
output$table1Item2 <- renderRHandsontable({
rhandsontable(data$df2, stretchH = "all") |>
hot_col(1, dateFormat = "YYYY-MM-DD", type = "date")
})
}
shinyApp(ui, server)