Reactive selectizeInput box fail to update correctly in Shiny 1.8.0, first value of previous allowed choices are kept
System details
Browser Version:
Output of sessionInfo():
R version 4.3.0 (2023-04-21)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.3 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=nb_NO.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=nb_NO.UTF-8
[6] LC_MESSAGES=en_US.UTF-8 LC_PAPER=nb_NO.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=nb_NO.UTF-8 LC_IDENTIFICATION=C
time zone: Europe/Oslo
tzcode source: system (glibc)
attached base packages:
[1] stats4 stats graphics grDevices utils datasets methods base
other attached packages:
[1] DT_0.30 shiny_1.8.0 fstcore_0.9.14 data.table_1.14.8
[5] RiboCrypt_1.5.1 ORFik_1.23.5 GenomicAlignments_1.36.0 Rsamtools_2.16.0
[9] Biostrings_2.69.2 XVector_0.40.0 SummarizedExperiment_1.30.1 Biobase_2.60.0
[13] MatrixGenerics_1.12.3 matrixStats_1.2.0 GenomicRanges_1.52.0 GenomeInfoDb_1.36.1
[17] IRanges_2.34.1 S4Vectors_0.38.1 BiocGenerics_0.46.0
loaded via a namespace (and not attached):
[1] RColorBrewer_1.1-3 shape_1.4.6 rstudioapi_0.14 jsonlite_1.8.4 magrittr_2.0.3
[6] shinyjqui_0.4.1 GenomicFeatures_1.52.0 rmarkdown_2.21 fs_1.6.2 GlobalOptions_0.1.2
[11] BiocIO_1.10.0 zlibbioc_1.46.0 vctrs_0.6.2 NGLVieweR_1.3.1 memoise_2.0.1
[16] RCurl_1.98-1.12 usethis_2.1.6 htmltools_0.5.5 S4Arrays_1.2.0 progress_1.2.2
[21] curl_5.0.0 sass_0.4.6 bslib_0.5.1 fontawesome_0.5.1 htmlwidgets_1.6.2
[26] plotly_4.10.1 cachem_1.0.8 mime_0.12 lifecycle_1.0.3 iterators_1.0.14
[31] pkgconfig_2.0.3 Matrix_1.6-4 R6_2.5.1 fastmap_1.1.1 clue_0.3-64
[36] GenomeInfoDbData_1.2.10 digest_0.6.31 colorspace_2.1-0 ps_1.7.5 shinycssloaders_1.0.0
[41] AnnotationDbi_1.62.1 DESeq2_1.40.1 pkgload_1.3.2 crosstalk_1.2.0 RSQLite_2.3.1
[46] filelock_1.0.2 fansi_1.0.4 httr_1.4.5 abind_1.4-5 compiler_4.3.0
[51] remotes_2.4.2 bit64_4.0.5 doParallel_1.0.17 BiocParallel_1.34.0 DBI_1.1.3
[56] pkgbuild_1.4.0 R.utils_2.12.2 biomaRt_2.56.0 sessioninfo_1.2.2 rappdirs_0.3.3
[61] DelayedArray_0.26.1 rjson_0.2.21 tools_4.3.0 httpuv_1.6.9 fst_0.9.8
[66] R.oo_1.25.0 glue_1.6.2 callr_3.7.3 restfulr_0.0.15 promises_1.2.0.1
[71] grid_4.3.0 cluster_2.1.4 generics_0.1.3 gtable_0.3.3 BSgenome_1.68.0
[76] R.methodsS3_1.8.2 tidyr_1.3.0 hms_1.1.3 xml2_1.3.4 utf8_1.2.3
[81] markdown_1.6 foreach_1.5.2 pillar_1.9.0 stringr_1.5.0 later_1.3.1
[86] circlize_0.4.15 dplyr_1.1.2 BiocFileCache_2.8.0 lattice_0.21-8 rtracklayer_1.60.0
[91] bit_4.0.5 tidyselect_1.2.0 ComplexHeatmap_2.16.0 locfit_1.5-9.7 miniUI_0.1.1.1
[96] knitr_1.42 gridExtra_2.3 xfun_0.39 devtools_2.4.5 stringi_1.7.12
[101] lazyeval_0.2.2 yaml_2.3.7 evaluate_0.20 codetools_0.2-19 tibble_3.2.1
[106] cli_3.6.1 xtable_1.8-4 processx_3.8.1 munsell_0.5.0 jquerylib_0.1.4
[111] biomartr_1.0.8.9000 Rcpp_1.0.10 dbplyr_2.3.2 png_0.1-8 XML_3.99-0.14
[116] parallel_4.3.0 ellipsis_0.3.2 shinyhelper_0.3.2 ggplot2_3.4.2 rclipboard_0.2.0
[121] blob_1.2.4 prettyunits_1.1.1 profvis_0.3.8 urlchecker_1.0.1 bitops_1.0-7
[126] viridisLite_0.4.2 scales_1.2.1 purrr_1.0.1 crayon_1.5.2 GetoptLong_1.0.5
[131] rlang_1.1.1 cowplot_1.1.1 KEGGREST_1.40.0 shinyjs_2.1.0
Example application or steps to reproduce the problem
library(shiny)
ui <- fluidPage(
titlePanel(tag("u", "Test"), "Test"),
selectizeInput(
inputId = "selectID",
label = "Select id type",
choices = c("Numeric", "Letters"),
selected = "Numeric",
multiple = FALSE
),
selectizeInput(
inputId = "library",
label = "Select libraries",
choices = as.character(seq(5)),
selected = 1,
multiple = TRUE
),
h3("And now!?"),
br(),
)
server <- function(input, output, session) {
observeEvent(input$selectID, {
if (input$selectID == "Numeric") {
choices <- as.character(seq(5))
} else {
choices <- LETTERS[1:5]
}
updateSelectizeInput(
inputId = "library",
choices = choices,
selected = choices[1],
server = TRUE
)
},
ignoreNULL = TRUE, ignoreInit = FALSE)
session$onSessionEnded(function() { stopApp() })
}
print(shinyApp(ui, server, options = list(launch.browser = TRUE)))
Describe the problem in detail
A new bug in 1.8.0, I can verify that this does not happen in 1.7.4, which I had before I updated today.
When you have a box (library) with selectable numbers 1,2,3,4,5 and another box (selectID) that defines id type of box (library) (numeric is default or character: i.e. changes the selection in (library) to A,B,C,D,E. The total allowed selection of (library) will not be A,B,C,D,E, but 1,A,B,C,D,E. If you flip back to numeric, the allowed options are then: A,1,2,3,4,5
Even though you restrict the types on updateSelectizeInput, this is clearly ignored as the first value of previous allowed choices are kept
This breaks our app on www.Ribocrypt.org
Hi @Roleren, thanks for the bug report!
One important detail: this only happens when server = TRUE. In this case, the full set of choices are kept back on the server because they could be potentially large and are only sent to the client app when requested. If you completely change the available choices, the client won't know that the current (about to be old) values are no longer valid, so it keeps those values as options.
We can do slightly better than the current situation when selected is provided. I've just added a bit of code in #3967 that will clear the current value of the select input before performing the choices update when selected is provided.
Here are two other options to get around this issue with released shiny:
-
Use fully client-side selectize inputs, i.e.
server = FALSE. -
Manually clear the selection before updating the choices and current value, but having an
observeEvent()that first clears the selection:choices <- reactive({ if (input$selectID == "Numeric") { as.character(seq(5)) } else { LETTERS[1:5] } }) observeEvent(choices(), { # Clear the selection before updating choices updateSelectizeInput( inputId = "library", selected = NULL, server = TRUE ) }) observeEvent(choices(), { updateSelectizeInput( inputId = "library", choices = choices(), selected = choices()[1], server = TRUE ) })
Thanks, this should solve the issue for now. As far as I understand, the old value is still kept if selected is not specified ?
I'm not sure if #3967 fixed this. I'm still having the same issue as explained in the original post with shiny v1.8.1.1 and development version.
@trangdata I just tried the reprex in the original post with shiny v1.8.1.1 and it worked for me as expected after #3967. If you're encountering a similar issue it might actually be a new or different problem. Can you please open a new issue with a reproducible example so we can take a look?
I ran the same reprex with shiny v1.8.1.1. Maybe I can clarify what I see a little bit:
When I first load the app, I have Numeric. I select libraries 1, 3, 5, then switch to Letters. Now, the selected library is A. However, when I click on the input box to select more libraries (expectedly only letters), I see 1, 3, 5 as options also.
Maybe I'm missing something obvious?!
I don't think it's that you missed something obvious, I had to re-read the issue again carefully to remember...
When I first load the app, I have Numeric. I select libraries 1, 3, 5, then switch to Letters. Now, the selected library is A. However, when I click on the input box to select more libraries (expectedly only letters), I see 1, 3, 5 as options also.
This part of the issue isn't fixed by #3967, because
when
server = TRUE... the full set ofchoicesare kept back on the server because they could be potentially large and are only sent to the client app when requested. If you completely change the availablechoices, the client won't know that the current (about to be old) values are no longer valid, so it keeps those values as options.
My recommendation for solving this part of the problem was to
Manually clear the selection before updating the choices and current value, but having an observeEvent() that first clears the selection
by adding the following to the server logic above the observeEvent() that sets the new selection and choices.
observeEvent(choices(), {
# Clear the selection before updating choices
updateSelectizeInput(
inputId = "library",
selected = NULL,
server = TRUE
)
})
Ah okay! Thank you for clarifying Garrick! I saw your workaround in the earlier comment but thought that #3967 fixed everything and I would not have to manually clear the selection before updating the choices. But it makes sense now. Thanks!