Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Externally link to specific tabPanel in Shiny App

Tags:

r

shiny

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)
  })
})
like image 373
Charlie Joey Hadley Avatar asked Oct 08 '15 16:10

Charlie Joey Hadley


2 Answers

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)
like image 177
JBlaz Avatar answered Oct 14 '22 03:10

JBlaz


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)

like image 3
DeanAttali Avatar answered Oct 14 '22 05:10

DeanAttali