Using shinyjs and bs4Dash in shiny applications

Hi there,

I made a fairly big shiny application with the shinydashboard package and am now trying to convert it to bs4Dash, the wonderful package developed by David Granjon. One of the key features of my application is the fact that shinydashboard::boxes load in a hidden state and are dynamically shown based on user inputs. This is possible with the help of the great shinyjs package developed by Dean Attali. Also, the hack I use to make it possible is to place the shinydashboard::boxes in divs with an id. I then use shinyjs::show and shinyjs::hide on the div's id.

It turns out that this hack does not really work with bs4Dash::bs4Cards. Well, it does work but there are visual issues when one puts bs4Dash::bs4Cards in divs. What I mean is that the element widths are not respected. Here is a reproducible example:

library(shiny)
library(bs4Dash)

body <- bs4DashBody(
  
  fluidRow(
    div(id = "card1", class = "card", bs4Card(title = "Card 1", width = 4)),
    div(id = "card2", class = "card", bs4Card(title = "Card 2", width = 4)),
    div(id = "card3", class = "card", bs4Card(title = "Card 3", width = 4))
  )
  
  
)

shiny::shinyApp(
  ui = bs4DashPage(
    old_school = FALSE,
    sidebar_collapsed = FALSE,
    controlbar_collapsed = FALSE,
    title = "Basic Dashboard",
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = bs4DashControlbar(),
    footer = bs4DashFooter(),
    body = body
  ),
  server = function(input, output) {}
)

After pointing out this issue to the author of bs4Dash (David Granjon), he sent me a "quick fix" code to add an id argument to bs4Dash::bs4Card, which is to be put in the body of the app:

tags$head(
    tags$script(
      "$(function(){
        var cards = $('.card');
        cards.each(function(e){
         $(cards[e]).attr('id', e);
        });
        console.log(cards)
      });
      "
    )
  )

So, I made a simple app to test out the functionality of the code. The application launches with 3 hidden bs4Cards and there are 3 buttons that are supposed to show them. Unfortunately, it does not work. Can anyone help me with it? Thank you

library(shiny)
library(bs4Dash)
library(shinyjs)
library(magrittr)

body <- bs4DashBody(
  
  useShinyjs(),
  
  tags$head(
    tags$script(
      "$(function(){
        var cards = $('.card');
        cards.each(function(e){
         $(cards[e]).attr('id', e);
        });
        console.log(cards)
      });
      "
    )
  ),
  
  fluidRow(
    bs4Card(id = "card1", title = "Card 1", width = 4) %>% shinyjs::hidden(),
    bs4Card(id = "card2", title = "Card 2", width = 4) %>% shinyjs::hidden(),
    bs4Card(id = "card3", title = "Card 3", width = 4) %>% shinyjs::hidden()
  ),
  
  actionButton(inputId = "button1", label = "Show Card 1"),
  actionButton(inputId = "button2", label = "Show Card 2"),
  actionButton(inputId = "button3", label = "Show Card 3")
)

shiny::shinyApp(
  
  ui = bs4DashPage(
    old_school = FALSE,
    sidebar_collapsed = FALSE,
    controlbar_collapsed = FALSE,
    title = "Basic Dashboard",
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = bs4DashControlbar(),
    footer = bs4DashFooter(),
    body = body
  ),
  
  server = function(input, output, session ){
    
    observeEvent(input$button1, {
      shinyjs::show(id = "card1")
    })
    
    observeEvent(input$button2, {
      shinyjs::show(id = "card2")
    })
    
    observeEvent(input$button3, {
      shinyjs::show(id = "card3")
    })
    
  }
)

David Granjon, helped me and provided the following code which works:

library(shiny)
library(bs4Dash)
library(shinyjs)
library(magrittr)
ā€‹
buttonList <- tagList(
  actionButton(inputId = "button1", label = "Show Card 1"),
  actionButton(inputId = "button2", label = "Show Card 2"),
  actionButton(inputId = "button3", label = "Show Card 3")
)
ā€‹
body <- bs4DashBody(
  
  useShinyjs(),
  
  tags$head(
    tags$script(
      "$(function(){
        var cards = $('.card');
        cards.each(function(e){
         $(cards[e]).attr('id', e);
         // hide the newly created id
         $('#' + e).hide();
        });
      });
      "
    )
  ),
  
  fluidRow(
    bs4Card(title = "Card 1", width = 4),
    bs4Card("card2", title = "Card 2", width = 4),
    bs4Card("card3", title = "Card 3", width = 4)
  ),
  
  buttonList
)
ā€‹
shiny::shinyApp(
  
  ui = bs4DashPage(
    old_school = FALSE,
    sidebar_collapsed = FALSE,
    controlbar_collapsed = FALSE,
    title = "Basic Dashboard",
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(),
    controlbar = bs4DashControlbar(),
    footer = bs4DashFooter(),
    body = body
  ),
  
  server = function(input, output, session ){
    lapply(seq_along(buttonList), function(i) {
      observeEvent(input[[buttonList[[i]]$attribs$id]], {
        print("Pouet")
        shinyjs::show(selector = paste0("#", i - 1))
      })
    })
  }
)
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.