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
Solution thanks to daattali
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)
})
})