12

I'm trying to collapse a box programmatically when an input changes. It seems that I only need to add the class "collapsed-box" to the box, I tried to use the shinyjs function addClass, but I don't know how to do that becuase a box doesn't have an id. Here as simple basic code that can be used to test possible solutions:

library(shinydashboard)

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
      box(collapsible = TRUE,p("Test")),
      actionButton("bt1", "Collapse")
  )
)

server <- function(input, output) {
  observeEvent(input$bt1, {
    # collapse the box
  })
}

shinyApp(ui, server)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
Geovany
  • 5,389
  • 21
  • 37

1 Answers1

24

I've never tried using boxes before so keep in mind that my answer might be very narrow minded. But I took a quick look and it looks like simply setting the "collapsed-box" class on the box does not actually make the box collapse. So instead my next thought was to actually click the collapse button programatically.

As you said, there isn't an identifier associated with the box, so my solution was to add an id argument to box. I initially expected that to be the id of the box, but instead it looks like that id is given to an element inside the box. No problem - it just means that in order to select the collapse button, we need to take the id, look up the DOM tree to find the box element, and then look back down the DOM tree to find the button.

I hope everything I said makes sense. Even if it doesn't, this code should still work and will hopefully make things a little more clear :)

library(shiny)
library(shinydashboard)
library(shinyjs)

jscode <- "
shinyjs.collapse = function(boxid) {
$('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(),
  dashboardBody(
    useShinyjs(),
    extendShinyjs(text = jscode, functions = "collapse"),
    actionButton("bt1", "Collapse box1"),
    actionButton("bt2", "Collapse box2"),
    br(), br(),
    box(id = "box1", collapsible = TRUE, p("Box 1")),
    box(id = "box2", collapsible = TRUE, p("Box 2"))
  )
)

server <- function(input, output) {
  observeEvent(input$bt1, {
    js$collapse("box1")
  })
  observeEvent(input$bt2, {
    js$collapse("box2")
  })
}

shinyApp(ui, server)
DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • Thank you @daattali it works!, Also thank you for the very useful shinyjs. – Geovany Aug 20 '15 at 17:06
  • I know this is a very old post but do we have to use dashboardPage for this to work? I've tried using it in a navbarPage and it doesn't work. Any work around for that? – Mridul Garg Apr 30 '18 at 21:40
  • @MridulGarg It should work anyway. Check you have added `useShinyjs()`! – asachet Apr 16 '19 at 11:36
  • 2
    Not sure this will be of help to anyone, but if your `shinydashboard::box` is in a shiny module, then you should: (i) set the id of the box with `ns("box1")` in the UI function of the module and (ii) use `js$collapse(session$ns("box1"))` in the server function of the module – SavedByJESUS Aug 22 '19 at 02:07
  • hi @dattali, your answer was fantastic but this was in 2015. Today in 2023 is it still relevant or will there be any native function available that you would know? The need of a custom javascript sends chills down any shiny developer who does not know JS. – Lazarus Thurston Feb 06 '23 at 19:28
  • Alas this solution no longer works as there seems to be a breaking change in shinyjs; `Error: shinyjs: extendShinyjs: functions argument must be provided.` – Lazarus Thurston Feb 06 '23 at 19:49
  • 1
    @LazarusThurston shinyjs did in fact have a breaking change since 2015, I edited the answer to reflect this. All that was needed was to add `functions = "collapse"` to the parameters of extendShinyjs – DeanAttali Feb 08 '23 at 22:31