Reputation: 1611
I have a simple app which uses a dynamic UI element, updateDateInput
, to ensure that the user is only able to select dates in the designated year. The selected date should always default to the first day of the selected year.
library(shiny)
library(tidyverse)
library(lubridate)
ui <- fluidPage(
selectInput("year", "Select Year:",
choices = 2010:2020, selected = 2015),
dateInput("date", "Select Date:", value = NULL)
)
server <- function(input, output, session) {
observeEvent(input$year,
updateDateInput(session, "date",
min = ymd(paste(input$year, "01-01", sep = "-")),
max = ymd(paste(input$year, "12-31", sep = "-")),
value = ymd(paste(input$year, "01-01", sep = "-"))))
}
shinyApp(ui, server)
When moving the selected year backwards (e.g 2015 - 2014), the selected date automatically updates to the first of the month. However, when the user moves the date forwards, from 2015 to 2016, the selected date default to null and the user needs to manually search to get to the current year dates.
Can anyone help me figure out why this is happening?
Upvotes: 2
Views: 337
Reputation: 12586
This is a nasty problem, and one that it took me ages to track down when it happened to me. The problem is that updateDateInput
appears to make changes that aren't atomic. That is, they don't occur all at once, but rather sequentially. Therefore, when changing more than one parameter of the input widget at at time, it's possible that the value
is momentarily invalid.
The trick is to make sure that the selected date is valid at all times during the update. That means making the changes in two stages, and in an order that depends on whether you're moving forwards or backwards in time.
Here's a working solution.
library(shiny)
library(tidyverse)
library(lubridate)
ui <- fluidPage(
selectInput("year", "Select Year:",
choices = 2010:2020, selected = 2015),
dateInput("date", "Select Date:", value = NULL)
)
server <- function(input, output, session) {
observeEvent(input$year, {
req(input$date, input$year)
# Are we going backwards or forwards?
if (as.numeric(input$year > year(input$date))) {
updateDateInput(
session,
"date",
max = ymd(paste(input$year, "12-31", sep = "-")),
value = ymd(paste(input$year, "01-01", sep = "-")),
)
updateDateInput(
session,
"date",
min = ymd(paste(input$year, "01-01", sep = "-"))
)
} else {
updateDateInput(
session,
"date",
min = ymd(paste(input$year, "01-01", sep = "-")),
value = ymd(paste(input$year, "01-01", sep = "-"))
)
updateDateInput(
session,
"date",
max = ymd(paste(input$year, "12-31", sep = "-"))
)
}
})
}
shinyApp(ui, server)
Upvotes: 3