Unable to select nothing value for select param with multiple and initial value
In a parameterized document, when the parameter input type is select and multiple: true is enabled and an initial value is set, it's not possible to select a null (or nothing/empty) option.
Here's a small reprex that creates two options. Launch Knit with parameters and deselect a and b in the first option. When knitting the document, params$mult_with_initial will be c("a", "b") rather than the expected "".
---
title: "Null Selection Issue"
output: html_document
params:
mult_with_initial:
label: Choose Multiple or None (starts selected, deselect options)
value: ["a", "b"]
input: select
multiple: true
choices: !r c("No selection" = "", letters[1:2])
mult_start_empty:
label: Choose Multiple or None (starts empty)
value: ""
input: select
multiple: true
choices: !r c("No selection" = "", letters[1:2])
---
Deselect `a` and `b` in the first option,
but note that they are added back as the default selection.
```{r}
str(params)
```
Expected behavior
```{r}
str(list(mult_with_initial = "", mult_start_empty = ""))
```
After removing a and b from the selection...

...the resulting document shows:

Session Info
─ Session info ───────────────────────────────────────────────────────────────────────────
setting value
version R version 3.6.1 (2019-07-05)
os macOS Mojave 10.14.6
system x86_64, darwin15.6.0
ui RStudio
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz America/New_York
date 2019-10-18
─ Packages ───────────────────────────────────────────────────────────────────────────────
package * version date lib source
assertthat 0.2.1 2019-03-21 [1] CRAN (R 3.6.0)
backports 1.1.5 2019-10-02 [1] CRAN (R 3.6.0)
callr 3.3.2 2019-09-22 [1] CRAN (R 3.6.0)
cli 1.1.0 2019-03-19 [1] CRAN (R 3.6.0)
clisymbols 1.2.0 2017-05-21 [1] CRAN (R 3.6.0)
crayon 1.3.4 2017-09-16 [1] CRAN (R 3.6.0)
desc 1.2.0 2018-05-01 [1] CRAN (R 3.6.0)
devtools * 2.1.0 2019-07-06 [1] CRAN (R 3.6.0)
digest 0.6.21 2019-09-20 [1] CRAN (R 3.6.0)
evaluate 0.14 2019-05-28 [1] CRAN (R 3.6.0)
fastmap 1.0.1 2019-10-08 [1] CRAN (R 3.6.0)
fs 1.3.1 2019-05-06 [1] CRAN (R 3.6.0)
glue 1.3.1 2019-03-12 [1] CRAN (R 3.6.0)
grkstyle 0.0.1 2019-08-12 [1] Github (gadenbuie/grkstyle@a141d39)
htmltools 0.4.0 2019-10-04 [1] CRAN (R 3.6.0)
httpuv 1.5.2 2019-09-11 [1] CRAN (R 3.6.0)
jsonlite 1.6 2018-12-07 [1] CRAN (R 3.6.0)
knitr 1.25 2019-09-18 [1] CRAN (R 3.6.0)
later 1.0.0 2019-10-04 [1] CRAN (R 3.6.0)
magrittr 1.5 2014-11-22 [1] CRAN (R 3.6.0)
memoise 1.1.0 2017-04-21 [1] CRAN (R 3.6.0)
mime 0.7 2019-06-11 [1] CRAN (R 3.6.0)
packrat 0.5.0-21 2019-09-30 [1] Github (rstudio/packrat@fe551ea)
pkgbuild 1.0.6 2019-10-09 [1] CRAN (R 3.6.0)
pkgload 1.0.2 2018-10-29 [1] CRAN (R 3.6.0)
prettyunits 1.0.2 2015-07-13 [1] CRAN (R 3.6.0)
processx 3.4.1 2019-07-18 [1] CRAN (R 3.6.0)
promises 1.1.0 2019-10-04 [1] CRAN (R 3.6.0)
prompt * 1.0.0 2019-08-12 [1] Github (gaborcsardi/prompt@b332c42)
ps 1.3.0 2018-12-21 [1] CRAN (R 3.6.0)
R6 2.4.0 2019-02-14 [1] CRAN (R 3.6.0)
Rcpp 1.0.2 2019-07-25 [1] CRAN (R 3.6.0)
remotes 2.1.0 2019-06-24 [1] CRAN (R 3.6.0)
rlang 0.4.0 2019-06-25 [1] CRAN (R 3.6.0)
rmarkdown 1.16 2019-10-01 [1] CRAN (R 3.6.0)
rprojroot 1.3-2 2018-01-03 [1] CRAN (R 3.6.0)
rsconnect 0.8.15 2019-07-22 [1] CRAN (R 3.6.0)
rsthemes 0.0.2 2019-10-14 [1] Github (gadenbuie/rsthemes@eaded46)
rstudioapi 0.10.0-9003 2019-10-14 [1] Github (rstudio/rstudioapi@206d524)
sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 3.6.0)
shiny * 1.4.0 2019-10-10 [1] CRAN (R 3.6.0)
testthat 2.2.1 2019-07-25 [1] CRAN (R 3.6.0)
usethis * 1.5.1 2019-07-04 [1] CRAN (R 3.6.0)
withr 2.1.2 2018-03-15 [1] CRAN (R 3.6.0)
xfun 0.10 2019-10-01 [1] CRAN (R 3.6.0)
xtable 1.8-4 2019-04-21 [1] CRAN (R 3.6.0)
yaml 2.2.0 2018-07-25 [1] CRAN (R 3.6.0)
[1] /Users/4468739/Library/R/3.6/library
[2] /Library/Frameworks/R.framework/Versions/3.6/Resources/library
A bit of context an explanation about this issues.
There is a special handling in the shiny app for params selection
https://github.com/rstudio/rmarkdown/blob/0af6b3556adf6e393b2da23c66c695724ea7bd2d/R/params.R#L413-L424
This means that when the input return NULL or same as the default, it will not be in the return value list values
values is what is returned by the app
https://github.com/rstudio/rmarkdown/blob/0af6b3556adf6e393b2da23c66c695724ea7bd2d/R/params.R#L434
https://github.com/rstudio/rmarkdown/blob/0af6b3556adf6e393b2da23c66c695724ea7bd2d/R/params.R#L15-L17
and we'll be merged with initial params from yaml https://github.com/rstudio/rmarkdown/blob/0af6b3556adf6e393b2da23c66c695724ea7bd2d/R/params.R#L37
So as input is empty, the mult_with_initial will not be part of value and so when list are merged the default value will be set in params which is what is return in the example above.
I believe this is also like that because selectInput() does not return empty string among the choices "" but returns NULL as nothing is selected.
Small shiny apps
library(shiny)
shinyApp(
ui = fluidPage(
selectInput("choice", "Choose Multiple or None (starts selected, deselect options)",
c(letters[1:2], "No selection" = ""),
selected = c("a", "b"),
multiple = TRUE
),
verbatimTextOutput("result")
),
server = function(input, output) {
output$result <- renderText({
capture.output(str(input$choice))
})
}
)
If I deselect the initial values, I don't get an empty character but I get NULL as a return value from selectInput

It seems like the expected behavior from the doc (https://shiny.rstudio.com/reference/shiny/1.7.0/selectInput.html#details)
In selectize mode, if the first element in choices has a value of "", its name will be treated as a placeholder prompt. For example: selectInput("letter", "Letter", c("Choose one" = "", LETTERS))
You would have to use selectize = FALSE in this case to make it works. Try with that:
params:
mult_with_initial:
label: Choose Multiple or None (starts selected, deselect options)
value: ["a", "b"]
input: select
multiple: true
choices: !r c("No selection" = "", letters[1:2])
selectize: false
Selecting no selection will return in the Rmd what you expect. It seems like using selectize expect a value to be selected.
So I don't think there is any issue here with rmarkdown as this behave as it would in shiny.
However, we could consider that in rmarkdown this would be a special case that when NULL is returned from a selectInput control, then we set it to empty string. Is it what you would do in a shiny app ?
What your thoughts based on this little investigation ?
Thanks
Wow I almost recognize this issue! 🤪
I think that the "no selection" intent should be carried through from the parameter selection app. After reading your explanation, I think rather than returning "" for both, it should be NULL, as it would be in a shiny app.
From reading the special handling logic, it seems like there might be scenarios where NULL is a sentinel value indicating that the user hasn't made a selection and so the default should be used. But in the case of the selectizeInput(), I think it would be safe to treat NULL as the returned value and do something similar to this:
default <- list(
choice = c("a", "b"),
other = c("d", "e")
)
params <- list()
# User deselected everything from the selectize choices
params["choice"] <- list(NULL)
# Another input still has the "default"
params$other <- NULL
rmarkdown:::merge_lists(default, params)
#> $other
#> [1] "d" "e"
#>
#> $choice
#> NULL