shinydashboard: Lost `tabItem` responsiveness when including inputs in `menuItem` - r

I got a dashboard where the tabItem that shows in the dashboardBody is dependant on the menuItem selected on the dashboardMenu, like this:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(dashboardHeader(title = "This works"),
dashboardSidebar(
sidebarMenu(
menuItem("item 1", tabName = "item1", icon = icon("th-list")),
menuItem("item 2", tabName = "item2", icon = icon("list-alt"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "item1",
tabsetPanel(id = "tabs1",
tabPanel("Tab1", plotOutput("1")),
tabPanel("Tab2", plotOutput("2"))
)),
tabItem(tabName = "item2",
tabsetPanel(id = "tabs2",
tabPanel("Tab3", plotOutput("3")),
tabPanel("Tab4", plotOutput("4"))
)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui, server)
However, as soon as I include an input in menuItem, this response is lost:
ui <- dashboardPage(dashboardHeader(title = "This doesn't work"),
dashboardSidebar(
sidebarMenu(
menuItem("item 1", tabName = "item1", icon = icon("th-list"),
checkboxInput("check", label = "check")),
menuItem("item 2", tabName = "item2", icon = icon("list-alt"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "item1",
tabsetPanel(id = "tabs1",
tabPanel("Tab1", plotOutput("1")),
tabPanel("Tab2", plotOutput("2"))
)),
tabItem(tabName = "item2",
tabsetPanel(id = "tabs2",
tabPanel("Tab3", plotOutput("3")),
tabPanel("Tab4", plotOutput("4"))
)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui, server)

Applying this answer to your example works. Here's the solution:
convertMenuItem <- function(mi,tabName) {
mi$children[[1]]$attribs['data-toggle']="tab"
mi$children[[1]]$attribs['data-value'] = tabName
mi
}
ui <- dashboardPage(dashboardHeader(title = "This works now"),
dashboardSidebar(
sidebarMenu(
convertMenuItem(menuItem("item 1", tabName = "item1", icon = icon("th-list"),
checkboxInput("check", label = "check")), tabName = "item1"),
menuItem("item 2", tabName = "item2", icon = icon("list-alt"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "item1",
tabsetPanel(id = "tabs1",
tabPanel("Tab1", plotOutput("1")),
tabPanel("Tab2", plotOutput("2"))
)),
tabItem(tabName = "item2",
tabsetPanel(id = "tabs2",
tabPanel("Tab3", plotOutput("3")),
tabPanel("Tab4", plotOutput("4"))
)
)
)
)
)
server <- function(input, output) {}
shinyApp(ui, server)

Related

Shiny dashboard preselect menuSubItem when clicking menuItem

When clicking on a menu item in the side bar I would like it to not only expand and show the menu sub items but also preselect the first one and show the corresponding tab item UI.
I know it is possible to define one item as selected and it will show when I start the app. To me this is confusing behaviour because the corresponding menu item does not appear as "selected" in the sidebar. My requirement goes further anyway since I want to preselect a menu sub item every time I click on a menu item.
library(shinydashboard)
library(shiny)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Table1" , tabname = "my_table1", icon = icon("table"),startExpanded = F,
menuSubItem("sub menu1",tabName = "subMenu1"),
menuSubItem("sub menu2",tabName = "subMenu2")
),
menuItem("Table2" , tabname = "my_table2", icon = icon("table"),startExpanded = F,
menuSubItem("sub menu3",tabName = "subMenu3"),
menuSubItem("sub menu4",tabName = "subMenu4", selected = T)
)
)),
dashboardBody(
tabItems(
tabItem(tabName = "my_table1",
h2("First Table")
),
tabItem(tabName = "my_table2",
h2("Second Table")
),
tabItem(tabName = "subMenu1",
h2("First tab")
),
tabItem(tabName = "subMenu2",
h2("Second tab")
),
tabItem(tabName = "subMenu3",
h2("Third tab")
),
tabItem(tabName = "subMenu4",
h2("Fourth tab")
)
)))
server <- function(input, output) {
}
shinyApp(ui, server)
Your sidebarMenu needs an id and your server function needs the session argument, so you can use:
updateTabItems(session, inputId="sidebarID", selected="subMenu1")
Please check the following:
library(shinydashboard)
library(shiny)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem("Table1" , tabname = "my_table1", icon = icon("table"), startExpanded = TRUE,
menuSubItem("sub menu1",tabName = "subMenu1", selected = TRUE),
menuSubItem("sub menu2",tabName = "subMenu2")
),
menuItem("Table2" , tabname = "my_table2", icon = icon("table"), startExpanded = FALSE,
menuSubItem("sub menu3",tabName = "subMenu3"),
menuSubItem("sub menu4",tabName = "subMenu4")
)
)),
dashboardBody(
tabItems(
tabItem(tabName = "my_table1",
h2("First Table")
),
tabItem(tabName = "my_table2",
h2("Second Table")
),
tabItem(tabName = "subMenu1",
h2("First tab")
),
tabItem(tabName = "subMenu2",
h2("Second tab")
),
tabItem(tabName = "subMenu3",
h2("Third tab")
),
tabItem(tabName = "subMenu4",
h2("Fourth tab")
)
)))
server <- function(input, output, session) {
observeEvent(input$sidebarItemExpanded, {
cat(paste("menuItem() currently expanded:", input$sidebarItemExpanded, "\n"))
if(input$sidebarItemExpanded == "Table1"){
updateTabItems(session, inputId="sidebarID", selected="subMenu1")
} else if(input$sidebarItemExpanded == "Table2"){
updateTabItems(session, inputId="sidebarID", selected="subMenu3")
}
})
observe({
cat(paste("tabItem() currently selected:", input$sidebarID, "\n"))
})
}
shinyApp(ui, server)
Furthermore please see the related docs.

input$sidebarItemExpanded does not work with convertMenuItem in R Shiny

For convertMenuItem, see reference here: https://stackoverflow.com/a/48212169
When I try to get the name of expanded menuItem, it doesn't work. Here's a standalone example:
library(shiny)
library(shinydashboard)
convertMenuItem <- function(mi,tabName) {
mi$children[[1]]$attribs['data-toggle']="tab"
mi$children[[1]]$attribs['data-value'] = tabName
if(length(mi$attribs$class)>0 && mi$attribs$class=="treeview"){
mi$attribs$class=NULL
}
mi
}
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", icon = icon("th"), tabName = "widgets"),
convertMenuItem(menuItem("Charts", tabName = "charts", icon = icon("bar-chart-o"), expandedName = "CHARTS",
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2")
), "charts")
),
textOutput("res")
),
dashboardBody(
tabItems(
tabItem("dashboard", "Dashboard tab content"),
tabItem("widgets", "Widgets tab content"),
tabItem("subitem1", "Sub-item 1 tab content"),
tabItem("subitem2", "Sub-item 2 tab content")
)
)
)
server <- function(input, output, session) {
output$res <- renderText({
req(input$sidebarItemExpanded)
paste("Expanded menuItem:", input$sidebarItemExpanded)
print(input$sidebarItemExpanded)
})
}
shinyApp(ui, server)
Is there a way to further modify this function so that Expanded Item functionality is also supported?
The following is a workaround to avoid using convertMenuItem.
Instead of it I'm using a hidden menuItem which is displayed once the childful menuItem "Charts" is expanded.
This way input$sidebarItemExpanded works as expected.
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", icon = icon("th"), tabName = "widgets"),
menuItem("Charts", tabName = "charts", icon = icon("bar-chart-o"), expandedName = "CHARTS",
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2")
),
hidden(menuItem("hiddenCharts", tabName = "hiddenCharts"))
),
textOutput("res")
),
dashboardBody(
useShinyjs(),
tabItems(
tabItem("dashboard", "Dashboard tab content"),
tabItem("widgets", "Widgets tab content"),
tabItem("hiddenCharts", "Charts Tab"),
tabItem("subitem1", "Sub-item 1 tab content"),
tabItem("subitem2", "Sub-item 2 tab content")
)
)
)
server <- function(input, output, session) {
observeEvent(input$sidebarItemExpanded, {
if(input$sidebarItemExpanded == "CHARTS"){
updateTabItems(session, "sidebarID", selected = "hiddenCharts")
}
})
output$res <- renderText({
req(input$sidebarItemExpanded)
paste("Expanded menuItem:", input$sidebarItemExpanded)
print(input$sidebarItemExpanded)
})
}
shinyApp(ui, server)

Link to a tab from dashboardBody

I am trying to have an action button within the Body of a tab (called "Widgets" in code) link to a different tab (called "data_table" in code). I know how to do this if the tab that I want to connect to, "data_table", is one of the menuItems that appears on the sidebarMenu. However, I do not wish for a link to the "data_table" tab to appear in the sidebar. I am stuck. I would have thought I need an "observeEvent"-type command which links the action button to the "data_table" tab. But I don't know what that is. Advice welcome. The code shows the UI side of things.
ui <- dashboardPage(
dashboardHeader(title = "My query"),
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets",
h2("Widgets"),
actionButton(inputId="seedata", label = "See data")),
tabItem(tabName = "data_table",
h2("Table with the data"))
)
)
)
server <- function(input, output, session) { }
shinyApp(ui, server)
Perhaps you are looking for something like this.
ui <- dashboardPage(
dashboardHeader(title = "My query"),
dashboardSidebar(
sidebarMenu(# Setting id makes input$tabs give the tabName of currently-selected tab
id = "tabs",
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", tabName = "widgets", icon = icon("th"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets", h2("Widgets"),
fluidRow(
tabBox(id = "tabset1", height = "850px", width=12, title = "My Data",
### The id lets us use input$tabset1 on the server to find the current tab
tabPanel("Table with the data", value="tab1", " ",
actionButton(inputId="seedata", label = "See data"),
uiOutput("dataTable")
),
tabPanel("Display Data Table", value="tab2", " ",
#uiOutput("someoutput")
DT::dataTableOutput("testtable")
)
)
)
))
)
)
server <- function(input, output, session) {
output$dataTable <- renderUI({
tagList(
div(style="display: block; height: 350px; width: 5px;",HTML("<br>")),
actionBttn(inputId="datatable",
label="Data Table",
style = "simple",
color = "success",
size = "md",
block = FALSE,
no_outline = TRUE
))
})
observeEvent(input$datatable, {
updateTabItems(session, "tabs", "widgets")
if (input$datatable == 0){
return()
}else{
## perform other tasks if necessary
output$testtable <- DT::renderDataTable(
mtcars,
class = "display nowrap compact", # style
filter = "top", # location of column filters
options = list( # options
scrollX = TRUE # allow user to scroll wide tables horizontally
)
)
}
})
observeEvent(input$datatable, {
updateTabsetPanel(session, "tabset1",
selected = "tab2")
})
}
shinyApp(ui, server)

Collapse dashboardSidebar menu after click

For the code below, I would like to have a menu (dashboardSidebar) that collapses when any menuItem but item2 is clicked.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(collapsed = TRUE, sidebarMenu(id = "tabs",
menuItem("item1", tabName = "item1", icon = icon("newspaper")),
menuItem("item2", tabName = "item2", icon = icon("tv"),
menuItem("item2_1", tabName = "item2_1", icon = icon("tasks")),
menuItem("item2_2", tabName = "item2_2", icon = icon("flag-checkered")),
menuItem("item2_3", tabName = "item2_3", icon = icon("user-clock"))))),
dashboardBody())
server <- function(input, output) {}
shinyApp(ui, server)
Thanks
Please check the following:
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(collapsed = TRUE, sidebarMenu(
id = "tabs",
menuItem("item1", tabName = "item1", icon = icon("newspaper")),
menuItem(
"item2",
tabName = "item2",
icon = icon("tv"),
menuItem("item2_1", tabName = "item2_1", icon = icon("tasks")),
menuItem(
"item2_2",
tabName = "item2_2",
icon = icon("flag-checkered")
),
menuItem("item2_3", tabName = "item2_3", icon = icon("user-clock"))
)
)),
dashboardBody(useShinyjs(),
tabItems(
tabItem(tabName = "item1",
h2("item1 tab content")),
tabItem(tabName = "item2_1",
h2("item2_1 tab content")),
tabItem(tabName = "item2_2",
h2("item2_2 tab content")),
tabItem(tabName = "item2_3",
h2("item2_3 tab content"))
))
)
server <- function(input, output, session) {
observeEvent(input$tabs, {
shinyjs::toggleClass(selector = "body", class = "sidebar-collapse")
}, ignoreInit = TRUE)
}
shinyApp(ui, server)
The only drawback is, that selecting the same menuItem twice doesn't collapse the sidebar, due to input$tabs remaining unchanged.

shinydashboard: menuSubItem not rendering at start in case of several menuSubItems

I found that menuSubItem content is not rendering in case of several (more than one) tabItems.
Minimal example demonstrating this behavior is below.
The desired behavior is to show content of the tabItem marked as selected = TRUE on startup. Now, the content shows up only after switching between menuSubItems in the sidebar.
How can I make it work?
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
uiOutput("body")
)
)
server <- function(input, output, session) {
output$menu <- renderMenu(
sidebarMenu(
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
output$body <- renderUI({
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
})
}
shinyApp(ui = ui, server = server)
Indeed, putting ui elements directly in UI solves it.
But the approach of putting everything inside ui is limited to situations that do not involve using reactive values. As I understand passing reactive value from server to ui is not possible in general (or limited to special cases). Please correct if I am wrong... Thanks
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
)
)
server <- function(input, output, session) {
output$menu <- renderMenu(
sidebarMenu(
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
}
shinyApp(ui = ui, server = server)
Renaming your output to something other than "body" helps - please see this.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
uiOutput("myBodyOutput")
)
)
server <- function(input, output, session) {
output$myBodyOutput <- renderUI({
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
})
output$menu <- renderMenu(
sidebarMenu(id = "sidebarID",
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
}
shinyApp(ui = ui, server = server)

Resources