Reputation: 23
I made a vector of choices. When I click on selectizeInput, I get choices in the same order as in my vector, but when I start typing in selectizeInput, the order of my choices is not the same as in my vector.
This is example of shiny app.
library(shiny)
choices <- c("First choice", "Second choice", "Choice third", "Fourth choice", "Choice fifth")
ui <- fluidPage(
selectizeInput("id",
"My input",
choices = choices,
multiple = TRUE,
options = list(placeholder = "All choices")
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
When I click on input choices are in this order. https://i.sstatic.net/1tScm.png
After I start typing "ch", the order of choices is not the same as first picture.
https://i.sstatic.net/k5ofy.png
How to make it so that are choices always in the same order?
Upvotes: 1
Views: 214
Reputation: 20399
First of all, the behaviour you see is intentional. selectize.js
(the underlying JavaScript
library for the selectInput
) uses sifter.js (yet another JavaScript
library responsible for the search behaviour).
The default setting of sifter
is to rank the search results according to their best score (where matches in the beginning of a string are scored better than in the middle of the string). Thus, you see that the order is "mixed" up and elements which have a match in the beginning are scored higher and are thus ranked at a higher position.
Luckily, you can override this behaviour with a bit of JavaScript
. The order in which results are returned can be controlled by a sortField
property in the settings of selectize.js
. By default this equals to $order
and looking into the documentation of selectize.js you can see that if there is no explicit $score
field, results will be sorted first according to the $score
and then according to the fields specified in the sortField
property.
Thus, all we need is to explicitly add a $score
field to scoreField
after $order
such that results are first sorted according to the intrinsic order and then to the score.
The last piece of the puzzle is to determine where we can call this custom JavaScript
b/c for obvious reasons the input element must be already existing before trying to change its settings.
The easiest place I found is to wait for shiny
to signal that an input element was bound.
To make a long story short, here's the code which assures that the search results are displayed in order:
library(shiny)
choices <- c("First choice", "Second choice", "Choice third", "Fourth choice",
"Choice fifth")
js <- HTML("
$(document).on('shiny:bound', function(evt) {
if (evt.target.id == 'id') {
evt.target.selectize.settings.sortField = [{field: '$order'}, {field: '$score'}];
}
});
"
)
ui <- fluidPage(
singleton(tags$head(tags$script(js))),
selectizeInput("id",
"My input",
choices = choices,
multiple = TRUE,
options = list(placeholder = "All choices")
)
)
server <- function(input, output, session) {
}
shinyApp(ui = ui, server = server)
Upvotes: 0