shiny icon indicating copy to clipboard operation
shiny copied to clipboard

order of initial value is not preserved by selectInput

Open FrancoisGuillem opened this issue 9 years ago • 5 comments

For instance consider the following code:

selectInput("myInput", "myInput", multiple = TRUE,
            choices = c("a", "b", "c"), 
            selected = c("b", "a"))

When the shiny server starts, the value of "myInput" will be c("a", "b") instead of c("b", "a"). This can be a problem if the order of the selected elements matters.

FrancoisGuillem avatar Nov 29 '16 16:11 FrancoisGuillem

A solution could be to store the initial value in a dedicated html attribute, for instance:

<select id="myInput" multiple="multiple" data-init-values="b,a">
...
</select>

FrancoisGuillem avatar Nov 30 '16 10:11 FrancoisGuillem

Along these same lines, it would be useful to have the choices respect factor levels:

library(shiny)

lvls <- c("b", "c", "a")
f1 <- factor(c("a", "b", "c"), levels = lvls)

ui <- fluidPage(
  selectizeInput(
    "d", "asdfas", choices = f1, multiple = TRUE
  )
)

server <- function(input, output) {}

shinyApp(ui, server)

cpsievert avatar Mar 06 '17 18:03 cpsievert

Do you know if this has been solved without any "workaround" ?

lbo34 avatar Aug 21 '18 19:08 lbo34

I just stumbled upon the same issue. My workaround for anyone that runs into the same bug:

selectizeInput("orderBug",
  "Order bug",
  choices = c("A", "B"),
  multiple = TRUE,
  options = list(
  # multiple issues in Shiny that I had to overcome here:
  # 1) order of items provided in "selected" not respected: https://github.com/rstudio/shiny/issues/1490
  # 2) I() used to avoid auto-unboxing values in jsonlite::toJSON() overwritten by Shiny
  #    to instead interpret character strings as JS code. Thus, we fall back to converting
  #    to a list instead.
  items = as.list(c("B", "A")),
)

Note that the as.list() is required if the selected choices is a length-1 character vector as shiny seems to use the auto_unbox option of jsonlite resulting in them being converted to JS strings instead of a length-1 array. We can't use the base::I() function recommended by jsonlite as this is already used by Shiny in this context to interpret strings as JS code (not sure why they don't use htmlwidgets::JS() function here).

fproske avatar Jun 03 '25 13:06 fproske

We've written a simple selectInput wrapper/drop-in replacement that preserves order selection during initialization as well as bookmark restoration. Code. Short blog post.

The solution is not far away from @fproske's, except that we pass the selection through the onInitialize selectize hook instead. That allows us to sidestep JSON serialization pitfalls. We also call shiny::restoreInput to preserve bookmarking.

mlechon avatar Oct 10 '25 06:10 mlechon