kileuskas
kileuskas

Reputation: 23

How to make same order of choices in selectizeInput while clicking or typing?

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

Answers (1)

thothal
thothal

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

Related Questions