It's possible to use anchor links in flat Shiny apps relatively easily - https://stackoverflow.com/a/28605517/1659890.
However, is it possible for an external link to target a specific tabPanel
of a navbarPage
in a Shiny app?
Consider the following test app: UI:
shinyUI(navbarPage(
"Anchor Test",
tabPanel(
"Panel 1", fluidPage(HTML(
paste(
"<p>I'm the first panel</p>","<p><a href='#irisPlotUI'>Link to irisPlotUI in panel 2</a></p>",
"<a href='#panel2'>Link to panel 2</a>",sep = ""
)
))
),
tabPanel("Panel 2", fluidPage(
"I'm the second panel", uiOutput("irisPlotUI")
),
value = "#panel2"),
tabPanel("Panel 3", "I'm a table!!!")
Server:
shinyServer(function(input, output) {
output$irisPlotUI <- renderUI(plotOutput("irisPlot"))
output$irisPlot <- renderPlot(plot(iris$Sepal.Length))
})
Using the method from the linked answer doesn't work, the id of irisPlotUI
is correct but is a child of the tabPanel
that the plot lives in.
The data-value
of the tabPanel
is given the value of "panel2"
through the use of the argument value
, however the Shiny app continues to give the tabPanel
a unique id that I don't know how to target.
I've examined the source of deployed Shiny apps, for instance https://martinjhnhadley.shinyapps.io/AnchorLinks, and found the actual link to the tabPanel
: https://internal.shinyapps.io/martinjhnhadley/AnchorLinks/?initialWidth=1074&childId=shinyapp#tab-8850-2
However, navigating directly to this link does not direct me to the tab either.
Are anchor links my only option in targeting parts of the app or is there a Shiny specific solution?
If not, how might I insert a script such as shown here https://stackoverflow.com/a/15637801/1659890 to allow javascript to be executed when landing on the Shiny app to select the tabPanel
in a similar manner to this https://groups.google.com/d/msg/shiny-discuss/sJlasQf71fY/RW7Xc8F02IoJ
Using daattali's answer I was able to find the following also from him - https://github.com/rstudio/shiny/issues/772#issuecomment-112919149
The following achieves exactly my needs, note that I have chosen to keep with the /?url=
convention he used:
UI.R
shinyUI(
navbarPage( "test", id = 'someID',
tabPanel("tab1", h1("page1")),
navbarMenu( "menu",
tabPanel('tab2a', value='nested1', h1("page2a")),
tabPanel('tab2b', value='nested2', h1("page2b")),
tabPanel('tab_sub', "foobar")
),
tabPanel("tab3", h1("page3"))
))
SERVER.R
url1 <- url2 <- ""
shinyServer(function(input, output, session) {
values <- reactiveValues(myurl = c(), parent_tab = "")
observe({
# make sure this is called on pageload (to look at the query string)
# and whenever any tab is successfully changed.
# If you want to stop running this code after the initial load was
# successful so that further manual tab changes don't run this,
# maybe just have some boolean flag for that.
input$someID
input$tab_sub_tabs
query <- parseQueryString(session$clientData$url_search)
url <- query$url
if (is.null(url)) {
url <- ""
}
# "depth" is how many levels the url in the query string is
depth <- function(x) length(unlist(strsplit(x,"/")))
# if we reached the end, done!
if (length(values$myurl) == depth(url)) {
return()
}
# base case - need to tell it what the first main nav name is
else if (length(values$myurl) == 0) {
values$parent_tab <- "someID"
}
# if we're waiting for a tab switch but the UI hasn't updated yet
else if (is.null(input[[values$parent_tab]])) {
return()
}
# same - waiting for a tab switch
else if (tail(values$myurl, 1) != input[[values$parent_tab]]) {
return()
}
# the UI is on the tab that we last switched to, and there are more
# tabs to switch inside the current tab
# make sure the tabs follow the naming scheme
else {
values$parent_tab <- paste0(tail(values$myurl, 1), "_tabs")
}
# figure out the id/value of the next tab
new_tab <- unlist(strsplit(url, "/"))[length(values$myurl)+1]
# easy peasy.
updateTabsetPanel(session, values$parent_tab, new_tab)
values$myurl <- c(values$myurl, new_tab)
})
})
I found the other answer a little difficult to follow so I created the example below. To navigate to the Data Availability tab, place "?a=b" to at the end of your url. For example if hosting the app on port 7436 the following link will take you directly to the Data Availability page. http://127.0.0.1:7436/?a=b
library(shinydashboard)
library(shiny)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(id = "container",
menuItem("Channels", tabName = "lt_channels"),
menuItem("Data Availability", tabName = "data_avail")
)),
dashboardBody(
tabItems(
tabItem(tabName = "lt_channels",
h1("Test Fail")),
tabItem(tabName = "data_avail",
h1("Test Pass"))
)
)
)
server <- function(session, input, output){
observe({
query <- parseQueryString(session$clientData$url_search)
query1 <- paste(names(query), query, sep = "=", collapse=", ")
print(query1)
if(query1 == "a=b"){
updateTabItems(session, inputId = "container", selected = "data_avail")
}
})
}
shinyApp(ui = ui, server = server)
You could add a search query parameter to the URL (eg. href='www.myapp.com?tab=tab2
), and in the app that is being linked you would have to add a bit of logic that changes to a specified tab on initialization if the search string is present (eg. look at session$clientData$url_search
and if it exists and there's a tab
variable, then use updateTabsetPanel()
to go to that tab)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With