1

my question relates to observing the event of toggling and untoggling of the header in bsCollapsePanel in shinyBS.

Lets consider following following app as an example:

library(shiny)
library(shinyBS)
server = function(input, output, session) {
    observeEvent(input$p1Button, ({
      updateCollapse(session, "collapseExample", open = "Panel 1")
    }))
    observeEvent(input$styleSelect, ({
      updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
    }))
    output$randomNumber <- reactive(paste0('some random number'))
  }


ui = fluidPage(
  sidebarLayout(
    sidebarPanel(HTML("This button will open Panel 1 using <code>updateCollapse</code>."),
                 actionButton("p1Button", "Push Me!"),
                 selectInput("styleSelect", "Select style for Panel 1",
                             c("default", "primary", "danger", "warning", "info", "success"))
    ),
    mainPanel(
      bsCollapse(id = "collapseExample", open = "Panel 2",
                 bsCollapsePanel("Panel 1", "This is a panel with just text ",
                                 "and has the default style. You can change the style in ",
                                 "the sidebar.", style = "info")
      ),
      verbatimTextOutput('randomNumber')
    )
  )
)

app = shinyApp(ui = ui, server = server)

I want the app to be able to print a random number (using R shiny reactivity) in the verbatimTextOutput('randomNumber') field every time I open bsCollapsePanel by clicking on Panel 1 header.

I was thinking that it may be possible using shinyjs package but have not found many examples of these two packages used together.

Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59
user974514
  • 552
  • 1
  • 7
  • 19

2 Answers2

2

Okay, Mike Wise was faster than me :) If for some reason my solution is also helpful let me know otherwise i delete it.

library(shiny)
library(shinyjs)
library(shinyBS)

ui = fluidPage(
  useShinyjs(),
  sidebarLayout(
    sidebarPanel(HTML("This button will open Panel1 using <code>updateCollapse</code>."),
                 actionButton("p1Button", "Push Me!"),
                 selectInput("styleSelect", "Select style for Panel1",
                             c("default", "primary", "danger", "warning", "info", "success"))
    ),
    mainPanel(
      bsCollapse(id = "collapseExample", open = "Panel 2",
                 bsCollapsePanel("Panel1", "This is a panel with just text ",
                                 "and has the default style. You can change the style in ",
                                 "the sidebar.", style = "info", id = "me23")
      ),
      verbatimTextOutput('randomNumber')
    )
  )
)

server = function(input, output, session) {
  observeEvent(input$p1Button, ({
    updateCollapse(session, "collapseExample", open = "Panel1")
  }))
  observeEvent(input$styleSelect, ({
    updateCollapse(session, "collapseExample", style = list("Panel1" = input$styleSelect))
  }))

  observe({
    runjs("function getAllElementsWithAttribute(attribute){
              var matchingElements = [];
              var allElements = document.getElementsByTagName('*');
              for (var i = 0, n = allElements.length; i < n; i++)
              {
              if (allElements[i].getAttribute(attribute) !== null)
              {
              // Element exists with attribute. Add to array.
              matchingElements.push(allElements[i]);
              }
              }
              return matchingElements;
              };
              ahref = getAllElementsWithAttribute('data-toggle');
              ahref[0].onclick = function() { 
                var nmbr = Math.random();
                Shiny.onInputChange('randomNumber', nmbr);
              };
          ")
  })
  output$randomNumber <- reactive(paste0(input$randomNumber))
}




shinyApp(ui = ui, server = server)

Javascript code you can find here: Get elements by attribute when querySelectorAll is not available without using libraries?

Community
  • 1
  • 1
Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59
  • I think it is useful code, albeit maybe overkill for this particular scenario. Might be more applicable to what he intends in the long run though. – Mike Wise Apr 19 '17 at 19:30
  • i agree i also tried first working with `input$collapseExample` but somehow i seemed have to miss smthg as it didnt work for me. +1 for your more elegant solution :). – Tonio Liebrand Apr 19 '17 at 19:35
  • 1
    Ditto for your more interesting solution. Studying it actually, will certainly be able to use that someday. – Mike Wise Apr 19 '17 at 19:39
  • 1
    Brilliant solution. I like the combination of shinyjs and shinyBS. Definitely will be useful for me. – user974514 Apr 21 '17 at 14:13
1

I am not completely sure what you want, but this might be close. These are the additions:

  • Added an observeEvent to monitor your Panel 1 header.
  • Added a reactiveValues to hold the "random number"
  • Incremented that value in the above observeEvent handler when Panel 1 is pushed.

Here is the code:

library(shiny)
library(shinyBS)
server = function(input, output, session) {
  rv <- reactiveValues(number=0)
  observeEvent(input$p1Button, ({
    updateCollapse(session, "collapseExample", open = "Panel 1")
  }))
  observeEvent(input$styleSelect, ({
    updateCollapse(session, "collapseExample", style = list("Panel 1" = input$styleSelect))
  }))
  observeEvent(input$collapseExample, ({
    rv$number <- rv$number+1
  }))
  output$randomNumber <- reactive(rv$number)
}


ui = fluidPage(
  sidebarLayout(
    sidebarPanel(HTML("This button will open Panel 1 using <code>updateCollapse</code>."),
                 actionButton("p1Button", "Push Me!"),
                 selectInput("styleSelect", "Select style for Panel 1",
                           c("default", "primary", "danger", "warning", "info", "success"))
    ),
    mainPanel(
      bsCollapse(id = "collapseExample", open = "Panel 2",
                 bsCollapsePanel("Panel 1", "This is a panel with just text ",
                                 "and has the default style. You can change the style in ",
                                 "the sidebar.", style = "info")
      ),
      verbatimTextOutput('randomNumber')
    )
  )
)
shinyApp(ui = ui, server = server)

And a screen shot:

enter image description here

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • Elegant solution. Even though after running it I realized that I want the number to change after I would close panel as well. But since I only mentioned opening the panel in my question and you were the first one to answer it would make sense for me to accept it. – user974514 Apr 21 '17 at 14:10
  • I would appreciate that. And feel free to post another question around additional requirements, I am sure someone will address it - including me if I find the time. – Mike Wise Apr 21 '17 at 14:12