Search code examples
rshinyshinydashboard

Shiny: Two conditional panels in a row - how to have them fill the entire row if only one is showing?


I have a fluid row that contains two conditional panels. I would to make it so that if only one is being displayed, it takes up the entire row (width = 12), whereas if both are showing they both get equal space (width = 6).

I have attempted to use multiple conditional panels based on logic of whether one or both are turned on, but it ends up showing all of the panels regardless of the value of either of the inputs.

When I comment out either the first two conditional panels OR the 3rd one, the logic works fine - so it isn't the individual logic, it's something that isn't working when all 3 are evaluated.

So, is there something I'm doing wrong here? Is there a better option than having multiple conditional panels for the same content, such as a method for having them automatically take up as much width as is available?

fluidRow(
      conditionalPanel(condition = "input.chart_toggle && !input.table_toggle",
                       box(title = "Chart",
                           width = 12,
                           collapsible = F,
                           collapsed = F,
                           plotOutput("newplot")
                      )
      ),
      conditionalPanel(condition = "input.table_toggle && !input.chart_toggle",
                       box(title = "Table",
                           width = 12,
                           collapsible = F,
                           collapsed = F,
                           DTOutput("table")
                       )
      ),
      
      conditionalPanel(condition = "input.chart_toggle && input.table_toggle",
                       box(title = "Chart",
                           width = 6,
                           collapsible = F,
                           collapsed = F,
                           plotOutput("newplot")
                       ),
      
                       box(title = "Table",
                           width = 6,
                           collapsible = F,
                           collapsed = F,
                           DTOutput("table")
                       )
      )

enter image description here


Solution

  • Having multiple identical ids for different inputs/outputs is never a good idea. It will most certainly result in unexpected behaviour.

    That said, using conditionalPanel seems to complicate things a bit.

    As @Meisam stated in the comments, you can use renderUI and then put the conditions there.

    Another alternative would be to use {shinyjs} to hide and show the cards, and then update them as required.

    Here is a reprex:

    shinyjs+updateCards showcase

    global.R

    library(shiny)
    

    ui.R

    ui <- bs4Dash::bs4DashPage(
      header = bs4Dash::dashboardHeader(),
      sidebar = bs4Dash::dashboardSidebar(),
      body = bs4Dash::dashboardBody(
        shinyjs::useShinyjs(),
        checkboxInput(
          inputId = "chart_toggle",
          label = "Show chart",
          value = TRUE
        ),
        checkboxInput(
          inputId = "table_toggle",
          label = "Show table",
          value = TRUE
        ),
        fluidRow(
          bs4Dash::bs4Card(
            id = "chart_card",
            title = "Chart",
            width = 6,
            collapsible = FALSE,
            plotOutput("newplot")
          ),
          bs4Dash::bs4Card(
            id = "table_card",
            title = "Table",
            width = 6,
            collapsible = FALSE,
            DT::DTOutput(outputId = "table")
          )
        )
      )
    )
    

    server.R

    server <- \(input, output, session) {
      output$newplot <- renderPlot({
        plot(
          x = iris$Sepal.Length,
          y = iris$Petal.Width,
          col = iris$Species,
          xlab = "Sepal Length",
          ylab = "Petal Width",
          pch = 19
        )
      })
      
      output$table <- DT::renderDT({
        DT::datatable(
          iris,
          options = list(scrollX = TRUE)
        )
      })
      
      observeEvent(c(input$chart_toggle, input$table_toggle), {
        chart_toggle <- input$chart_toggle
        table_toggle <- input$table_toggle
        if (chart_toggle && !table_toggle) {
          shinyjs::hide(id = "table_card")
          bs4Dash::updatebs4Card(
            id = "chart_card",
            action = "update",
            options = list(width = 12)
          )
          shinyjs::show(id = "chart_card")
        }
    
        if (!chart_toggle && table_toggle) {
          shinyjs::hide(id = "chart_card")
          bs4Dash::updatebs4Card(
            id = "table_card",
            action = "update",
            options = list(width = 12)
          )
          shinyjs::show(id = "table_card")
        }
    
        if (chart_toggle && table_toggle) {
          bs4Dash::updatebs4Card(
            id = "chart_card",
            action = "update",
            options = list(width = 6)
          )
          bs4Dash::updatebs4Card(
            id = "table_card",
            action = "update",
            options = list(width = 6)
          )
          shinyjs::show(id = "chart_card")
          shinyjs::show(id = "table_card")
        }
        
        if (!chart_toggle && !table_toggle) {
          shinyjs::hide(id = "chart_card")
          shinyjs::hide(id = "table_card")
        }
      })
    }