Reputation: 3056
Is there a more native way of remembering the last active tab, when changing tabsets (here in header / navbar), to return to it upon tabset change in bs4Dash
?
library(shiny)
library(bs4Dash)
library(shinyjs)
ui <- bs4DashPage(
header = bs4DashNavbar(
title = "Remember Last Tab in bs4Dash",
tags$div(
id = "tabset-container",
style = "display: flex; justify-content: center; gap: 10px; padding: 10px;",
div(
id = "tabset1",
style = "background-color: #0073B7; padding: 10px; color: white; cursor: pointer;", "Tab Set 1"
),
div(
id = "tabset2",
style = "background-color: #0073b7; padding: 10px; color: white; cursor: pointer;", "Tab Set 2"
)
)
),
sidebar = bs4DashSidebar(
uiOutput("sidebar_menu")
),
body = bs4DashBody(
useShinyjs(),
tags$script(HTML("
$(document).on('shiny:connected', function (event) {
Shiny.setInputValue('activeTabSet', 'tabset1')
})
Shiny.addCustomMessageHandler('selectTab', function(tabName) {
var sidebar = document.querySelector('[data-widget=\"treeview\"]');
var tab = sidebar.querySelector('[data-value=\"' + tabName + '\"]');
if (tab) tab.click();
});
Shiny.addCustomMessageHandler('tabsetReady', function(tabset) {
setTimeout(function() {
Shiny.setInputValue('tabsetReady', tabset, {priority: 'event'});
}, 100);
});
")),
bs4TabItems(
bs4TabItem(tabName = "tab1_1", h2("Content for Tab 1.1")),
bs4TabItem(tabName = "tab1_2", h2("Content for Tab 1.2")),
bs4TabItem(tabName = "tab2_1", h2("Content for Tab 2.1")),
bs4TabItem(tabName = "tab2_2", h2("Content for Tab 2.2"))
)
)
)
server <- function(input, output, session) {
# Reactive values to store the last visited tab for each tabset
lastTabs <- reactiveValues(tabset1 = "tab1_1", tabset2 = "tab2_1")
shinyjs::onclick("tabset1", {
runjs('Shiny.setInputValue("activeTabSet", "tabset1")')
})
shinyjs::onclick("tabset2", {
runjs('Shiny.setInputValue("activeTabSet", "tabset2")')
})
# Dynamically render the sidebar menu based on the active tabset
output$sidebar_menu <- renderUI({
req(input$activeTabSet)
if (input$activeTabSet == "tabset1") {
bs4SidebarMenu(
id = "sidebar",
bs4SidebarMenuItem("Tab 1.1", tabName = "tab1_1", icon = icon("dashboard")),
bs4SidebarMenuItem("Tab 1.2", tabName = "tab1_2", icon = icon("chart-bar"))
)
} else if (input$activeTabSet == "tabset2") {
bs4SidebarMenu(
id = "sidebar",
bs4SidebarMenuItem("Tab 2.1", tabName = "tab2_1", icon = icon("globe")),
bs4SidebarMenuItem("Tab 2.2", tabName = "tab2_2", icon = icon("cogs"))
)
}
})
observeEvent(input$sidebar, {
req(input$activeTabSet)
if (input$activeTabSet == "tabset1") {
lastTabs$tabset1 <- input$sidebar
} else if (input$activeTabSet == "tabset2") {
lastTabs$tabset2 <- input$sidebar
}
})
observeEvent(input$activeTabSet, {
req(input$activeTabSet)
session$sendCustomMessage("tabsetReady", input$activeTabSet)
})
observeEvent(input$tabsetReady, {
req(input$tabsetReady)
if (input$tabsetReady == "tabset1") {
session$sendCustomMessage("selectTab", lastTabs$tabset1)
} else if (input$tabsetReady == "tabset2") {
session$sendCustomMessage("selectTab", lastTabs$tabset2)
}
})
}
shinyApp(ui, server)
Upvotes: 2
Views: 213
Reputation: 1219
Answer in "more native way", without extra javascript
library(shiny)
library(bs4Dash)
ui <- bs4DashPage(
header = bs4DashNavbar(
title = "Remember Last Tab in bs4Dash",
tags$div(
id = "tabset-container",
style = "display: flex; justify-content: center; gap: 10px; padding: 10px;",
bs4Dash::actionButton("tabset1",
"Tab Set 1",
style = "background-color: #0073b7; padding: 10px; color: white; cursor: pointer;"
),
bs4Dash::actionButton("tabset2",
"Tab Set 2",
style = "background-color: #0073b7; padding: 10px; color: white; cursor: pointer;"
)
)
),
sidebar = bs4DashSidebar(
uiOutput("sidebar_menu")
),
body = bs4DashBody(
bs4TabItems(
bs4TabItem(tabName = "tab1_1", h2("Content for Tab 1.1")),
bs4TabItem(tabName = "tab1_2", h2("Content for Tab 1.2")),
bs4TabItem(tabName = "tab2_1", h2("Content for Tab 2.1")),
bs4TabItem(tabName = "tab2_2", h2("Content for Tab 2.2"))
)
)
)
server <- function(input, output, session) {
lastTabs <- reactiveValues(tabset1 = "tab1_1",
tabset2 = "tab2_1",
activeTabSet="tabset1"
)
updateTab.fct <- function (param_input, lastTabs_input) {
if (!(is.null(param_input)) && param_input >0 ) {
if (!is.null(lastTabs_input)) {
updatebs4TabItems(
session,
inputId = "sidebar",
selected =lastTabs_input[[lastTabs_input$activeTabSet]]
)
}
}
}
observeEvent(input$tabset1, {
lastTabs$activeTabSet <- "tabset1"
lastTabs$tabset1 <- lastTabs[[lastTabs$activeTabSet]]
updateTab.fct(input$tabset1,lastTabs)
}, ignoreInit = TRUE)
observeEvent(input$tabset2, {
lastTabs$activeTabSet <- "tabset2"
lastTabs$tabset2 <- lastTabs[[lastTabs$activeTabSet]]
updateTab.fct(input$tabset2,lastTabs)
}, ignoreInit = TRUE)
observeEvent(input$sidebar, {
if (is.null(input$sidebar) ) {
# lastTabs$activeTabSet <- "tabset1"
lastTabs$tabset1 <- lastTabs[[lastTabs$activeTabSet]]
updateTab.fct(1,lastTabs)
} else if (lastTabs$activeTabSet == "tabset1") {
lastTabs$tabset1 <- input$sidebar
} else if (lastTabs$activeTabSet == "tabset2") {
lastTabs$tabset2 <- input$sidebar
}
}, ignoreInit = FALSE, ignoreNULL = FALSE)
output$sidebar_menu <- renderUI({
if (ifelse (is.null(lastTabs$activeTabSet),"tabset1", lastTabs$activeTabSet) == "tabset1") {
bs4SidebarMenu(
id = "sidebar",
bs4SidebarMenuItem("Tab 1.1", tabName = "tab1_1", icon = icon("dashboard")),
bs4SidebarMenuItem("Tab 1.2", tabName = "tab1_2", icon = icon("chart-bar"))
)
} else {
bs4SidebarMenu(
id = "sidebar",
bs4SidebarMenuItem("Tab 2.1", tabName = "tab2_1", icon = icon("globe")),
bs4SidebarMenuItem("Tab 2.2", tabName = "tab2_2", icon = icon("cogs"))
)
}
})
}
shinyApp(ui, server)
Upvotes: 2
Reputation: 4182
library(shiny)
library(bs4Dash)
ui <- bs4DashPage(
header = bs4DashNavbar(
title = "Remember Last Tab in bs4Dash",
tags$div(
id = "tabset-container",
style = "display: flex; justify-content: center; gap: 10px; padding: 10px;",
lapply(c("tabset1", "tabset2"), function(tabset) {
div(
id = tabset,
style = "background-color: #0073B7; padding: 10px; color: white; cursor: pointer;",
toupper(tabset)
)
})
)
),
sidebar = bs4DashSidebar(
uiOutput("sidebar_menu")
),
body = bs4DashBody(
tags$head(tags$script(HTML("
$(document).ready(function() {
// Bind click events for tabsets dynamically
['tabset1', 'tabset2'].forEach(function(tabset) {
$('#' + tabset).on('click', function() {
Shiny.setInputValue('activeTabSet', tabset);
});
});
});
// Push tab to URL
Shiny.addCustomMessageHandler('updateURL', function(tab) {
history.pushState(null, '', '?tab=' + tab);
});
"))),
bs4TabItems(
bs4TabItem(tabName = "tab1_1", h2("Content for Tab 1.1")),
bs4TabItem(tabName = "tab1_2", h2("Content for Tab 1.2")),
bs4TabItem(tabName = "tab2_1", h2("Content for Tab 2.1")),
bs4TabItem(tabName = "tab2_2", h2("Content for Tab 2.2"))
)
)
)
server <- function(input, output, session) {
# Reactive values to track last visited tabs
lastTabs <- reactiveValues(tabset1 = "tab1_1", tabset2 = "tab2_1")
activeTabSet <- reactiveVal("tabset1")
# Helper: Update sidebar menu based on active tabset
updateSidebarMenu <- function(tabset) {
tabs <- if (tabset == "tabset1") {
list(
list("Tab 1.1", "tab1_1", "dashboard"),
list("Tab 1.2", "tab1_2", "chart-bar")
)
} else {
list(
list("Tab 2.1", "tab2_1", "globe"),
list("Tab 2.2", "tab2_2", "cogs")
)
}
bs4SidebarMenu(
id = "sidebar",
lapply(tabs, function(tab) {
bs4SidebarMenuItem(tab[[1]], tabName = tab[[2]], icon = icon(tab[[3]]))
})
)
}
# Reactive: Determine initial tab from URL
initialTab <- reactive({
parseQueryString(session$clientData$url_search)$tab %||% "tab1_1"
})
# Observe changes in active tabset
observeEvent(input$activeTabSet, {
activeTabSet(input$activeTabSet)
updatebs4TabItems(
session,
inputId = "sidebar",
selected = lastTabs[[input$activeTabSet]]
)
})
# Render the sidebar dynamically
output$sidebar_menu <- renderUI({
updateSidebarMenu(activeTabSet())
})
# Track and save the active tab within the current tabset
observeEvent(input$sidebar, {
lastTabs[[activeTabSet()]] <- input$sidebar
session$sendCustomMessage('updateURL', input$sidebar)
})
# Initialize the app with the correct tab on load
observeEvent(initialTab(), {
updatebs4TabItems(session, inputId = "sidebar", selected = initialTab())
}, once = TRUE)
}
shinyApp(ui, server)
Upvotes: 1