Reputation: 2222
I'm writing a Shiny app with fluidRow
s and I want to create a dynamic number of columns in the app. I can make columns appear and disappear correctly, but I don't know how to also make them resize accordingly. The desired outcome is that all columns have width 4 if there are 3 of them and width 6 if there are 2. The number of possible columns is 2, 3, or 4 so I don't need to account for more variability than that.
I know that I can probably do it by passing the entire column set through renderUI
. However, that would require me to define the contents of the columns in server.R and I'd rather avoid that.
See below for a minimal code example of my app:
library(shiny)
ui <- fluidPage(
titlePanel("Dynamic Columns"),
sidebarLayout(
sidebarPanel(
selectInput("column_count", "Number of Columns", 2:4, 2),
submitButton("Go")
),
mainPanel(
fluidRow(
column(3, "This is column 1"),
column(3, "This is column 2"),
conditionalPanel(
condition = "input.column_count >= 3",
column(3, "This is column 3")
),
conditionalPanel(
condition = "input.column_count == 4",
column(3, "This is column 4")
)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Upvotes: 1
Views: 777
Reputation: 669
One way might be to alter the css classes using javascript. I wrote a short js script that calculates the width using the selected value (i.e., 2, 3, 4) and the maximum bootstrap.js columns (i.e., 12): 12 / value
, and then updates the class with the new width: col-sm-*
. I explicitly named which columns should be resized by adding the class target-column
. (You can use any name you like. Make sure it is updated in the js function.). The event is trigged by the submit button.
Here's your example with the javascript. (I wrapped the app in tagList
).
library(shiny)
ui <- tagList(
fluidPage(
titlePanel("Dynamic Columns"),
sidebarLayout(
sidebarPanel(
selectInput("column_count", "Number of Columns", 2:4, 2),
submitButton("Go")
),
mainPanel(
fluidRow(
column(3, "This is column 1", class = "target-column"),
column(3, "This is column 2", class = "target-column"),
conditionalPanel(
condition = "input.column_count >= 3",
column(3, class = "target-column", "This is column 3")
),
conditionalPanel(
condition = "input.column_count == 4",
column(3, class = "target-column", "This is column 4")
)
)
)
),
tags$script(
type = "text/javascript",
"
const btn = document.querySelector('button[type=submit]');
const input = document.getElementById('column_count');
btn.addEventListener('click', function(event) {
// calculate new width
w = 12 / input.options[input.selectedIndex].value;
console.log('new width', w);
// update classes
const columns = document.querySelectorAll('.target-column');
columns.forEach(function(column) {
column.className = 'col-sm-' + w + ' target-column';
});
})
"
)
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Upvotes: 2