-1

I'm looking to stop a dropdownbutton (shinywidgets) from opening when the button is clicked based on a condition. This to avoid renderUI errors on missing input for content on the dropdownButton modal panel.

When a user clicks on a dropdownButton, it normally opens a panel. In my case, this panel contains renderUIelements that depend on various variables. If these variables do not exist yet, the renderUIswill cause errors to spit out.

What I would like to know is whether there is a way to look at the click observeEvent(input$MydropdownButton, { ....}) and then completely stop it from opening the panel if a condition is not met, rather than toggle it to close immediately (not working version)

What I plan to do, is to give the user a sweetalert instead that informs the user of which options he has to create or load the needed data. And I know how to do the message, purely looking to stop the opening part in an 'if else' way

  • I know I can use shinyjs::disable('MydropdownButton') inside an observer with ifstatement to block the use of the button, but this would not allow me to trigger the sweetalerton a click anymore
  • I also know I can adjust all my renderUIs not to render if the needed input is missing, but by now there are a lot of renderUIs involved, and I'm:
    • A: afraid to make a mess of the code, and
    • B: eager to find out if there is a way in general to stop the opening of dropdownButtons

I've tried something like this:

observeEvent(input$MydropdownButton, { 
if(!is.null(values$neededData)) { 'just open the dropdownbutton' } 
else { toggleDropdownButton('TestDrop')
'run sweetalert code'} 
})

But the toggleDropdownButtonwill only close the dropdownButtonpanel once it's already triggered to open, and thus shiny tried to renderthe uielement, with the resulting error, rather than block it from opening.

Here are a full serverand uicode files to demonstrate it calling for non-existing numbers.

SERVER file

shinyServer = function(input, output, session) {

  values <- reactiveValues()

  output$Reset_Threshold <- renderUI({
    if(values$randomNr == 2) { actionButton(inputId = "Reset_Threshold", label = icon("undo")) }
    else if(values$randomNr == 1) { actionButton(inputId = "Reset_Threshold", label = icon("table"))  }
  })

  observeEvent(input$TestDrop, { 
    if(!is.null(values$randomNr )) { print('no problems')}
    else {  toggleDropdownButton('TestDrop') 
      # Run other code here to alert user.
    }
    })
}

UI file

library(shiny)
library(shinyWidgets)

    ui <- fluidPage(
      dropdownButton(inputId= "TestDrop", 
                     uiOutput('Reset_Threshold'),
                     icon = icon("table"), tooltip = tooltipOptions(title = "Click"))
      )

```
Mark
  • 2,789
  • 1
  • 26
  • 66

1 Answers1

1

The error is not caused by toggling the dropdown menu but referencing a variable randomNr that doesn't exist. I added the variable and also a sweet dialog when the data is not ready in the server logic now it works.

But do note that it's not possible to stop the dropdown menu from opening. We still need to close it. If you want to block it from opening completely, you can conditionally render a regular Shiny actionButton when your data is not ready and will still trigger an event. Just make sure only one button is rendered under different condition and they should use the same input ID.

function(input, output, session) {
  values <- reactiveValues(Filter_df = NULL, randomNr = 0)

  output$Reset_Threshold <- renderUI({
    if (values$randomNr == 2) {
      actionButton(inputId = "Reset_Threshold", label = icon("undo"))
    }
    else if (values$randomNr == 1) {
      actionButton(inputId = "Reset_Threshold", label = icon("table"))
    }
  })

  observeEvent(input$TestDrop, {
    if (!is.null(values$Filter_df)) {
      print("no problems")
    } else {
      toggleDropdownButton("TestDrop")
      # Run other code here to alert user.
      sendSweetAlert(session, "data not ready")
    }
  })
}

EDIT

Just render a different button now. I'm using a single file app.R

library(shiny)
library(shinyWidgets)

ui <- fluidPage(
  uiOutput("button")
)

server <- function(input, output, session) {
  values <- reactiveValues(Filter_df = NULL, randomNr = 0)

  output$button <- renderUI({
    if (values$randomNr == 1) {
      dropdownButton(
        inputId = "dropdown",
        actionButton(inputId = "Reset_Threshold", label = icon("table")),
        icon = icon("table"), tooltip = tooltipOptions(title = "Click")
      )
    } else {
      actionButton(
        inputId = "alert",
        NULL,
        icon = icon("table")
      )
    }
  })

  observeEvent(input$alert, {
    sendSweetAlert(session, "data not ready")
  })
}

shiny::shinyApp(ui, server)
lkq
  • 2,326
  • 1
  • 12
  • 22
  • The fact that randomNr does not exist is the whole point here, in order to create the error. At some point in my app random Nr will exist of course, once user has loaded it.. If it does exist like in your answer, I wouldn't need the alert message to begin with. Perhaps it was unclear because I left 'values$Filter_df in the code where it should have been values$ranomNr as well. – Mark Feb 06 '19 at 17:37
  • I was actually thinking about the edit you just wrote, conditional rendering of either Regular button vs dropdownButton. Another option would be to put the content of the popup in 2 conditional panels. One that is empty and active if data is missing, the other one if data is all there. Both of them quite possible, perhaps a bit more work for the first one. Perhaps there is indeed no direct way to block the opening without disabling the dropdownbutton completely – Mark Feb 06 '19 at 17:40
  • @Mark There is no way to completely block it because that's how the dropdownbutton is designed. However, you said there is an error when trying to work around it using my solution. Are you considering the very rapid display of an empty dropdown menu and then going away an error or something else? – lkq Feb 06 '19 at 17:42
  • @Mark conditionally rendering an action button is actually very easy to achieve. the dropdownbutton is an wrapper of actionbutton itself. – lkq Feb 06 '19 at 17:43
  • @Mark See my edit for conditionally rendering buttons. – lkq Feb 06 '19 at 17:49
  • I know i know. My app is filled with about 150 of such conditional buttons that change color, shape, icons etc. – Mark Feb 06 '19 at 17:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188013/discussion-between-mark-and-keqiang-li). – Mark Feb 06 '19 at 17:51