Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow duplicate selections with InputSelect #4129

Open
TearsRfuel opened this issue Sep 17, 2024 · 4 comments
Open

Allow duplicate selections with InputSelect #4129

TearsRfuel opened this issue Sep 17, 2024 · 4 comments

Comments

@TearsRfuel
Copy link

Please allow the option for selectInput / selectizeInput to select the same items repeatedly. There are applications where this is needed. The selection list should remain unchanging.

Thats basically all. Thank you

@gadenbuie
Copy link
Member

Could you give an example that motivates the feature request? Even better would be to include a small app as well.

@TearsRfuel
Copy link
Author

TearsRfuel commented Sep 17, 2024

Could you give an example that motivates the feature request? Even better would be to include a small app as well.

In my case, I am creating an application to visualize win-rate data for competitive gaming. In this case, teams can choose their character prior to the match, and these characters can be identical. I.e. you can have a matchup of A+A vs B+B and users might like to know what the win rate of A+A vs B+B is. There was actually a similar request here: #2939

So in this example app, the user might want to select A, B, C or D twice

choices <- c("A", "B", "C", "D")
ui <- fluidPage(
  selectizeInput(inputId = "choose_your_character", 
              "your character(s)",
              choices = choices,
              options = list(maxItems = 2),
              multiple = TRUE)
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

Thank you

@gadenbuie
Copy link
Member

gadenbuie commented Sep 18, 2024

Here's a version (try it on shinylive.io) building on the solution provided in #2939 that updates the select input with new choices based on the original choice values so that the options "A", "B", "C" and "D" always appears as choices.

library(shiny)

choices <- setNames(nm = c("A", "B", "C", "D"))

clean_choices <- function(x) {
  # removes the extra index we add to each choice
  sub("__\\d+__$", "", x)
}

new_choices <- function(current) {
  cli::cli_inform("-----")
  cli::cli_inform("current: {.val {current}}")
  cli::cli_inform("clean: {.val {clean_choices(current)}}")
  
  selected <- unique(clean_choices(current))
  
  if (length(selected) == 0) {
    # Nothing selected, return base choices
    return(choices)
  }

  choices_not_selected <- setdiff(choices, selected)
  new_choices <- sprintf(
    "%s__%d__",
    selected,
    floor(runif(1) * 1e5) # A random id for the new choice
  )
  cli::cli_inform("new choices: {.val {new_choices}}")

  # New choices must include the current selection, plus the new
  # choices to fill in for what's been selected, plus the base
  # original choices.
  x <- union(current, new_choices)
  x <- union(choices, x)
  x <- sort(x)
  names(x) <- clean_choices(x)
  cli::cli_inform("updated choices: {.val {x}}")
  x
}

ui <- fluidPage(
  selectizeInput(
    inputId = "choose_your_character", 
    "your character(s)",
    choices = choices,
    options = list(maxItems = 10, plugins = "remove_button"),
    multiple = TRUE
  ),
  verbatimTextOutput("debug")
)

server <- function(input, output, session) {
  observe({
    updateSelectInput(
      session,
      "choose_your_character",
      choices = new_choices(input$choose_your_character),
      selected = isolate(input$choose_your_character)
    )
  })

  output$debug <- renderPrint({
    req(input$choose_your_character)
    picked <- clean_choices(input$choose_your_character)
    cat("You've picked", paste(picked, collapse = ", "))
  })
}

shinyApp(ui, server)

Clearly, this isn't the most ideal solution, but it solves the problem at hand. I'd prefer an upstream feature in selectize.js, but that seems unlikely. I'd recommend rolling this into a Shiny module if you plan to use it in your own app.

@ismirsehregal
Copy link
Contributor

In a scenario like this maybe shinyjqui (see orderInput()) or sortable are more suitable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants