javascriptrshinyshinywidgets

How to avoid easy closing of a shinyWidgets::dropdown()?


I would like to close a dropdown only when clicking a button within it. I tried like this:

library(shiny)
library(shinyWidgets)

ui <- fluidPage(
  
  tags$head(
    tags$script(
      HTML("
        $(document).ready(function() {
          $('.dropdown').on('hide.bs.dropdown', function (e) {
            return false;
          });
          
          $('#closeDropdownBtn').click(function() {
            $('.dropdown').removeClass('show');
          });
        });
      ")
    )
  ),
  
  dropdown(
    "Your contents goes here ! You can pass several elements",
    circle = TRUE, status = "danger", icon = icon("gear"), width = "300px",
    animate = animateOptions(enter = "fadeInDown", exit = "fadeOutUp", duration = 1),
    actionButton("closeDropdownBtn", "Fechar Dropdown")
  )
  
)

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

shinyApp(ui, server)
 

I would like the dropdown to close only with this button, and not when I click on another element on the screen, whatever it may be. Also, how to create an overlay on the screen when the dropdown is present, just like with a modal. I would like to replicate this behavior in the dropdown:

library(shiny)
library(shinyWidgets)

ui <- fluidPage()

server <- function(input, output, session) {
  
  showModal(
    
    modalDialog(
      
      "TEXT",
      
      actionButton("id1", "Close"),
      
      easyClose = FALSE
      
    )
    
  )
  
  observeEvent(input$id1, {
    
    removeModal()
    
  })
  
}

shinyApp(ui, server) 

Solution

  • The dropdown function from shinyWidgets does not create a Bootstrap dropdown. The Bootstrap dropdown can be obtained with dropdownButton. If you use dropdownButton, then this code works:

    $(document).ready(function() {
      $(".dropdown").on("hide.bs.dropdown", function(e) {
        alert("test");
      });
    
      $(".dropdown").on("click", "#closeDropdownBtn", function() {
        $(".dropdown").dropdown("toggle");
      });
    });
    

    Note that the selector of your closeDropdownBtn in the definition of the "onclick" event is "deferred". This is needed because this button is not visible when the app is initialized.

    You can also toggle this Bootstrap dropdown from R with the shinyWidgets function toggleDropdownButton.

    Now if you replace alert("test") with return false, this will work but then there is a problem: this will also work when clicking the button, so the button will no longer play its role. Here is a solution to this problem:

      tags$head(
        tags$script(
          HTML("
            $(document).ready(function() {
              var btnHasBeenClicked = false;
              $('.dropdown').on('hide.bs.dropdown', function (e) {
                if(!btnHasBeenClicked) {
                  return false; 
                } else {
                  btnHasBeenClicked = false;
                }
              });
              
              $('.dropdown').on('click', '#closeDropdownBtn', function() {
                btnHasBeenClicked = true;
                $('.dropdown').dropdown('toggle');
              });
            });
          ")
        )
      )