javascriptcssrshinyshinywidgets

How to replace choices of PickerInput with "all" when all of them are selected and display them only if "all" is clicked?


In the shiny app below when all pickerInput() choices are selected then instead of their names as choices inside the pickerInput() I would like to display the word "all" as choice and when you click on it, then all three choices shall be displayed. If we can make it work with selectInput() no problem but the printed output should not be affected. How can I do it?

library(shiny)
library(shinyWidgets)
ui <- fluidPage(
  
  uiOutput("pick"),
  verbatimTextOutput("PR")
)

server <- function(input, output, session) {
  output$pick<-renderUI({
    pickerInput(
      inputId = "p9",
      label = "Health Insurance",
      choices = unique(as.character(iris$Species)),
      width = "150px",
      selected = unique(as.character(iris$Species)),
      multiple = TRUE,
      options = list(
        `actions-box` = TRUE,
        `deselect-all-text` = "None",
        `select-all-text` = "All",
        `none-selected-text` = "zero"
      )
    )
  })
  output$PR<-renderPrint({
    input$p9
  })
}

shinyApp(ui, server)

Solution

  • This is an example based on this good answer. We use a clickHandler here which changes the style of the dropdown-item between display: block and display: none depending on when the container All is clicked. Note that by the initialisation of the app the items are only hidden behind All if all choices are selected.

    enter image description here

    library(shiny)
    library(shinyWidgets)
    
    js <- HTML(
        "
    $(function() {
      let observer = new MutationObserver(callback);
    
      function clickHandler(evt) {
        if ($('.dropdown-item').css('display') == 'block') {
            $('.dropdown-item').on('click', clickHandler).css('display', 'none');
        } else {
            $('.dropdown-item').on('click', clickHandler).css('display', 'block');
        }
      }
    
      function callback(mutations) {
          for (let mutation of mutations) {
              if (mutation.type === 'childList') {
                  $('.dropdown-header').on('click', clickHandler).css('cursor', 'pointer');
                  if ($('#p9 option').length == $('#p9 :selected').length) {
                      $('.dropdown-item').on('click', clickHandler).css('display', 'none');
                  }
              }
          }
      }
    
      let options = {
        childList: true,
      };
    
      observer.observe($('.inner')[0], options);
    })
    "
    )
    
    choices <- list("All" = unique(as.character(iris$Species)))
    
    ui <- fluidPage(
        tags$head(tags$script(js)),
        pickerInput(
            inputId = "p9",
            label = "Health Insurance",
            choices = choices,
            width = "150px",
            selected = unlist(unname(choices)),
            multiple = TRUE,
            options = list(
                `actions-box` = TRUE,
                `deselect-all-text` = "None",
                `select-all-text` = "All",
                `none-selected-text` = "zero"
            )
        ),
        verbatimTextOutput("PR")
    )
    
    server <- function(input, output, session) {
        output$PR <- renderPrint({
            input$p9
        })
    }
    
    shinyApp(ui, server)