【发布时间】:2016-01-06 10:16:09
【问题描述】:
在扁平的 Shiny 应用程序中使用锚链接相对容易 - https://stackoverflow.com/a/28605517/1659890。
但是,外部链接是否可以在 Shiny 应用中针对特定的 tabPanel 或 navbarPage?
考虑以下测试应用: 用户界面:
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!!!")
服务器:
shinyServer(function(input, output) {
output$irisPlotUI <- renderUI(plotOutput("irisPlot"))
output$irisPlot <- renderPlot(plot(iris$Sepal.Length))
})
使用链接答案中的方法不起作用,irisPlotUI 的 id 是正确的,但它是情节所在的 tabPanel 的孩子。
tabPanel 中的data-value 通过使用参数value 被赋予"panel2" 的值,但是Shiny 应用程序继续为tabPanel 提供一个我不知道的唯一ID如何定位。
我检查了已部署的 Shiny 应用程序的来源,例如 https://martinjhnhadley.shinyapps.io/AnchorLinks,并找到了指向 tabPanel 的实际链接:https://internal.shinyapps.io/martinjhnhadley/AnchorLinks/?initialWidth=1074&childId=shinyapp#tab-8850-2
但是,直接导航到此链接也不会将我定向到选项卡。
锚链接是我定位应用程序部分的唯一选择,还是有一个 Shiny 特定的解决方案?
如果不是,我如何插入一个脚本,例如此处显示的https://stackoverflow.com/a/15637801/1659890,以允许在登陆 Shiny 应用程序时执行 javascript,以与此 https://groups.google.com/d/msg/shiny-discuss/sJlasQf71fY/RW7Xc8F02IoJ 类似的方式选择 tabPanel
感谢 daattali 的解决方案
使用 daattali 的回答,我还可以从他那里找到以下内容 - https://github.com/rstudio/shiny/issues/772#issuecomment-112919149
以下内容完全符合我的需求,请注意,我选择遵守他使用的/?url= 约定:
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"))
))
服务器.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)
})
})
【问题讨论】:
-
我忘记了我写的那段代码 :) 我认为这段代码对于你的需要来说过于复杂了,除非你有很多选项卡并且每个选项卡都可以有嵌套的选项卡并且你不提前知道选项卡的名称。我写的那个解决方案是专门针对这种一般情况的。在您的情况下,如果您只有一级选项卡(与嵌套选项卡相比),那么大部分代码都是不必要的
-
@daattali 啊,好吧,对于这个最小的工作示例来说确实如此,但真正闪亮的应用程序有很多级别。不过好暴力。我个人认为这是其他人会从中受益并且很难找到的东西,值得写博客吗?
-
我计划很快写一篇关于许多不同的中级到高级闪亮技术的博客,其中将包括我经常看到的许多常见问题以及用于解决这些问题的代码的 sn-ps 以及解释。我已经有这个了:)