Reputation: 153
I want a hyperlink to work in practical terms just as a tab button would. This is my code so far (it has two normal tabs and a "hyperlink tab"):
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("Tab 1", tabName = "tab1", icon = icon("home")),
menuItem("Tab 2", tabName = "tab2", icon = icon("chart-bar")),
sidebarUserPanel(
actionLink("show_hidden_tab", "Show Hidden Tab")
)
)
),
dashboardBody(
uiOutput("hidden_tab_ui")
)
)
server <- function(input, output, session) {
hiddenTabContent <- reactiveVal(F)
observeEvent(input$show_hidden_tab, {
hiddenTabContent(!hiddenTabContent())
})
observeEvent(input$tabs, {
hiddenTabContent(F)
updateTabItems(session, "tabs", selected = input$tabs)
})
output$hidden_tab_ui <- renderUI({
if(hiddenTabContent()){
h2("Hidden Tab Content")
}else{
tabItems(
tabItem(tabName = "tab1",
h2("Tab 1 Content")
),
tabItem(tabName = "tab2",
h2("Tab 2 Content")
)
)
}
})
}
shinyApp(ui, server)
It almost works properly, except for the fact that when the app is launched, the content of tab 1 is not displayed until the user switches to tab 2, and then goes back to tab 1
How can I fix this and make the first tab's content visible as soon as the app is launched?
Upvotes: 0
Views: 48
Reputation: 1965
Below is an option where you can use shinyjs::hidden
to hide the menuItem.
Then you can use your actionLink
as a way to show the hidden tab item by using updateTabItems
.
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("Tab 1", tabName = "tab1", icon = icon("home")),
menuItem("Tab 2", tabName = "tab2", icon = icon("chart-bar")),
hidden(menuItem("Tab 3", tabName = "hidden_tab", icon = icon("chart-bar"))),
sidebarUserPanel(
actionLink("show_hidden_tab", "Show Hidden Tab")
)
)
),
dashboardBody(
useShinyjs(),
tabItems(
tabItem(tabName = "tab1",
h2("Tab 1 Content")
),
tabItem(tabName = "tab2",
h2("Tab 2 Content")
),
tabItem(tabName = "hidden_tab",
h2("Hidden Content")
)
)
)
)
server <- function(input, output, session) {
# display hidden tab when action link is clicked
observeEvent(input$show_hidden_tab, {
updateTabItems(session, "tabs", "hidden_tab")
})
}
shinyApp(ui, server)
Example:
Upvotes: 1
Reputation: 6663
shihydashboard::tabItems()
shows that behavior when the tabs are created dynamically with shiny::renderUI()
. You can insert some Javascript that waits for the browser to load the tabs and then activate the first tab. I modified your code below to do that.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("Tab 1", tabName = "tab1", icon = icon("home")),
menuItem("Tab 2", tabName = "tab2", icon = icon("chart-bar")),
sidebarUserPanel(
actionLink("show_hidden_tab", "Show Hidden Tab")
)
)
),
dashboardBody(
tags$script(
HTML(
"
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
waitForElm('#shiny-tab-tab1').then((elm) => {
//console.log('Element is ready');
//console.log(elm.textContent);
elm.classList.add('active');
});
"
)),
uiOutput("hidden_tab_ui")
)
)
server <- function(input, output, session) {
hiddenTabContent <- reactiveVal(F)
observeEvent(input$show_hidden_tab, {
hiddenTabContent(!hiddenTabContent())
})
observeEvent(input$tabs, {
hiddenTabContent(F)
updateTabItems(session, "tabs", selected = input$tabs)
})
output$hidden_tab_ui <- renderUI({
if(hiddenTabContent()){
h2("Hidden Tab Content")
}else{
tabItems(
tabItem(tabName = "tab1",
h2("Tab 1 Content")
),
tabItem(tabName = "tab2",
h2("Tab 2 Content"))
)
}
})
}
shinyApp(ui, server)
I noticed that there are more issues with this solution than just the first tab not being shown on page load:
active
and can not be clicked before another menu item is clicked.I think you might be better off not using renderUI()
to create the tabs. Instead, create three tabs in the UI definition, but skip the menu item for the third (hidden) tab. Attach an onlick
event to the actionLink
that execute a Javascript function which:
Here are some Javascript snippets for you to toy with:
When tab 2 is active/displayed, the code below will show tab 1 and hide tab 2.
document.querySelector("#shiny-tab-tab1").classList.add('active');
document.querySelector("#shiny-tab-tab2").classList.remove('active');
This code will deactivate all sidebar menu items, making them clickable.
menu_items = document.querySelector('.sidebar-menu').getElementsByTagName('li');
menu_items_arr = [...menu_items];
menu_items_arr.map(d => d.classList.remove('active'))
Upvotes: 1