In the below R Shiny code, the below HTML/CSS section at the top of the ui
is very important in keeping the width of the sidebar panel fixed while the main panel contracts/expands to match the window size as the user adjusts the window, while allowing certain objects like plots to automatically adjust in size, both expanding and contracting (it works great, I don’t want to lose this functionality):
tags$head(
tags$style(HTML("
.sidebar {
flex-shrink: 0;
}
.main-panel {
flex-grow: 1;
margin-left: 20px;
resize: both;
overflow: auto;
}
.main-panel > div {
width: 100%;
height: 100%;
}
"))
)
However, this above code snippet and the overflow = "visible"
specification in the rhandsontable()
function in the server section cause the “Add series” action button to be placed far below the user input table hottable_1
, as shown in the below image. I comment out either of the above and I either lose the important fixed sidebar panel and adjustable size main panel/plots, or the dropdown menu in the second row of input table hottable_1
is truncated when the user clicks on it. But if I comment out either of the above the action button in correctly placed under hottable_1
.
How can I move the “Add series” action button so it is placed immediately beneath hottable_1
, while keeping the functionality of the above HTML/CSS snippet and not truncating the dropdown menu when the user clicks on it? Preferable the dropdown would cover part of the action button; once the user makes the dropdown selection the dropdown retracts anyway revealing the action button.
Code:
library(jsonlite)
library(rhandsontable)
library(shiny)
ui <-
fluidPage(
tags$head(
tags$style(HTML("
.sidebar {
flex-shrink: 0;
}
.main-panel {
flex-grow: 1;
margin-left: 20px;
resize: both;
overflow: auto;
}
.main-panel > div {
width: 100%;
height: 100%;
}
"))
),
titlePanel(""),
div(
style = "display: flex; align-items: flex-start;",
div(class = "sidebar",wellPanel()),
div(
class = "main-panel",
"Parent tab", value = 'parent_tab',
tabsetPanel(
tabPanel(
"Child tab",
rHandsontableOutput('hottable_1'),
actionButton("addSeries","Add series"),
)
)
)
)
)
server <- function(input, output, session) {
seriesTbl_1 <- reactiveVal(
data.frame(
'Series1' = c(1, NA_character_),
row.names = c("Row_A", "Row_B")
)
)
choiceSelect <- toJSON(c('Choice A', 'Choice B', 'Choice C', 'Choice D', 'Choice E'))
observeEvent(input$hottable_1, {
seriesTbl_1(hot_to_r(input$hottable_1))
tbl <- seriesTbl_1()
})
output$hottable_1 <- renderRHandsontable({
tbl <- seriesTbl_1()
colNames <- paste0("Series", 1:ncol(tbl))
colnames(tbl) <- colNames
rhandsontable(
tbl,
overflow = "visible"
) %>%
hot_table(id = "hottable_1") %>%
htmlwidgets::onRender(sprintf("
function(el, x) {
var hot = this.hot;
var listElements = %s;
hot.updateSettings({
cells: function (row, col, prop) {
var cellProperties = {};
if (row === 1) {
cellProperties.type = 'dropdown';
cellProperties.source = listElements;
}
return cellProperties;
}
});
}
", choiceSelect))
})
observeEvent(input$addSeries, {
newSeriesCol_1 <- data.frame(c(1, NA_character_))
names(newSeriesCol_1) <- paste("Series", ncol(seriesTbl_1()) + 1)
seriesTbl_1(cbind(seriesTbl_1(), newSeriesCol_1))
})
seriesTbl_1_DF <- reactive({
tbl <- seriesTbl_1()
colNames <- paste0("Series", 1:ncol(tbl))
colnames(tbl) <- colNames
tbl
})
}
shinyApp(ui, server)