2

I have the following Shiny app:

library(shiny)

shinyApp(
  ui <- shinyUI(
    navbarPage("X-men",
               tabPanel("",icon = icon("home", lib = "glyphicon")  ),
               tabPanel("Plot")
            )),
  server <- shinyServer(function(input, output) {})
)
# Run the application 
shinyApp(ui = ui, server = server)

It produces:

enter image description here

As stated there. How can I direct the page to www.google.com after clicking Home button tabPanel()?


Update

After using Phi's html centric way latest method:

enter image description here

neversaint
  • 60,904
  • 137
  • 310
  • 477

2 Answers2

5

A UI-only solution

There's no need to use reactive logic to redirect. We just want to put a link in the html.


Sometimes shiny lets you forget that what you're really doing is just writing html on the ui.

For example, if we print the output of navbarPage to the console we get:

> navbarPage("X-men",
+            tabPanel("",icon = icon("home", lib = "glyphicon")  ),
+            tabPanel("Plot")
+ )
<nav class="navbar navbar-default navbar-static-top" role="navigation">
  <div class="container-fluid">
    <div class="navbar-header">
      <span class="navbar-brand">X-men</span>
    </div>
    <ul class="nav navbar-nav">
      <li class="active">
        <a href="#tab-8961-1" data-toggle="tab" data-value="">
          <i class=" glyphicon glyphicon-home"></i>

        </a>
      </li>
      <li>
        <a href="#tab-8961-2" data-toggle="tab" data-value="Plot">Plot</a>
      </li>
    </ul>
  </div>
</nav>
<div class="container-fluid">
  <div class="tab-content">
    <div class="tab-pane active" data-value="" data-icon-class="glyphicon glyphicon-home" id="tab-8961-1"></div>
    <div class="tab-pane" data-value="Plot" id="tab-8961-2"></div>
  </div>
</div>

The issue here is that the function navbarPage is applying some logic, it assumes that you only put tabPanel objects up there and it is doing something very special with the objects (it's creating a link in that spot, so any link we put inside that will get nullified). We can change that in one of two ways.

1) Write HTML using the tag and/or tags objects and make your own function

The first is simply to rewrite the navbarPage function in a way that produces the kind of output you're after.

You can look up the html for making a bootstrap navbar page and replicate it using ?tags or ?tag

(This is a great way to add new functionality to shiny. I wrote a package to speed this process by turning an html string into equivalent shiny functions: https://github.com/shapenaji/midas). But for something like this, that's overkill.

2) Hack in the desired object to the output of the function.

Here, we really just want to replace that home object in the header with a link, so lets just do that.

We save the output of the navbar function.

Then we replace that part of the object with our desired hack ...err... link.

A shiny object, like the output of navbarPage is just a list, and we can navigate our way to the bottom in the same way we would navigate a list.

(In this one, we have to dig a little bit to get down to the object. It's fairly deep in the nested list. But you can explore the object in the console to replace the parts you're after. I just peeled the list one at a time.)

(I have removed the shinyUI and shinyServer functions, as those wrappers are no longer necessary in the current version of shiny)

library(shiny)

shinyApp(

  ui = {
      page <- 
        navbarPage("X-men",id = "navibar",
                   tabPanel("placeholder"),
                   tabPanel("Plot",value = "plot"),
                   selected = "plot"
        )
      # Replace the second object in the navbar with the link
      page[[3]][[1]]$children[[1]]$children[[2]]$children[[1]] <- 
        tags$li(tags$a(
          href = 'http://google.com', 
          icon("home", lib = "glyphicon")
          )
        )
      # Finally return the page object, modified
      page
  },

  server = function(input, output, session) {
    # No server code necessary (yet...)
  }
)

How can I modify when navbarPage() is wrapped under fixedPage()

Answer: Change what you're modifying, the entire navbar page is inside the fixed page now, which adds page[[3]][[1]]$children[[1]] to the beginning

page[[3]][[1]]$children[[1]][[3]][[1]]$children[[1]]$children[[2]]$children[[1]] <- 
      tags$li(
        tags$a(
          href = 'http://google.com', 
          icon("home", lib = "glyphicon")
        )
      )

EDIT 2: A Cleaner way to do it:

library(shiny)

shinyApp(

  ui = {
      page <- 
        navbarPage("X-men",id = "navibar",
                   tabPanel("placeholder"),
                   tabPanel("Plot",value = "plot"),
                   selected = "plot"
        )
      # Replace the second object in the navbar with the link
      page[[3]][[1]]$children[[1]]$children[[2]]$children[[1]] <- 
        tags$li(tags$a(
          href = 'http://google.com', 
          icon("home", lib = "glyphicon")
          )
        )
      # Finally return the page object, wrapped by fixedPage
      fixedPage(page)
  },

  server = function(input, output, session) {
    # No server code necessary (yet...)
  }
)
Shape
  • 2,892
  • 19
  • 31
  • How can I modify your code if the `navbarPage` is wrapped under `fixedPage` See my update edit on your post. – neversaint Apr 06 '17 at 07:21
  • 1
    Is the fixed page Necessary? If so, then the link is in a slightly different place. Though honestly I would just write your own function at that point. Bootstrap navpages are quite simple. But let me update for the fixed page at least – Shape Apr 06 '17 at 07:25
  • Thanks a lot. I really appreciate that. My original app was in `fixedPage()` I simplify the code for simplification. – neversaint Apr 06 '17 at 07:26
  • `tabPanel("placeholder"),` this is not necessary right? – neversaint Apr 06 '17 at 07:36
  • 1
    @neversaint well, technically no. You could do it by adding it between the first and second elements. but it's easier to replace a location in a list that already exists than to add it inside a list between two elements. – Shape Apr 06 '17 at 07:39
  • 2
    @neversaint also, if you are embedding this inside an existing app, you can also just put a `uiOutput` inside the fixed page. And then create a second `renderUI` to pass the entire navbar in, completely self-contained. – Shape Apr 06 '17 at 07:43
  • Can you give example for your last comment with `uiOutput insides the fixed page` ? – neversaint Apr 06 '17 at 13:07
  • 1
    @neversaint While that's possible, I just realized, you can just stick the page inside the `fixedPage` when you return it, see edit – Shape Apr 06 '17 at 13:56
3

There are many ways you can accomplish this in R and Shiny. Here's one :

library(shiny)
shinyApp(
shinyUI(
uiOutput("navigate")
),

shinyServer(function(input, output, session) {
output$navigate <- renderUI({
  fixedPage(
    navbarPage("X-men",id = "navibar",
               tabPanel("",icon = icon("home", lib = "glyphicon"),value = "home"),
               tabPanel("Plot",value = "plot"),
               selected = "plot"
    )
  )
})
observeEvent(input$navibar,{
  if(input$navibar == "home"){
    browseURL("https://www.google.com")
  }
})
})
)

Basically all thats happening is that the observeEvent() function is triggered when the tab is clicked on opening a browser window to the URL.Here's also an example of using ui.R and server.R rather than a single file.

ui.R

library(shiny)

shinyUI(
fluidPage(
navbarPage("X-men",id = "navibar",
                         tabPanel("",icon = icon("home", lib =  "glyphicon"),value = "home"),
                         tabPanel("Plot",value = "plot"),
                         selected = "plot"
)
)
)

server.R

library(shiny)

shinyServer(function(input, output) {
observeEvent(input$navibar,{
if(input$navibar == "home"){
  browseURL("https://www.google.com")
}
})
})

Indeed we can also do this in a more html centric way, as Shape suggested, with a much simpler :

library(shiny)

shinyApp(
ui <- shinyUI(
navbarPage("X-men",
           tabPanel(tags$a(href = 'http://google.com', icon("home", lib = "glyphicon"))),
           tabPanel("Plot")
        )),
server <- shinyServer(function(input, output) {})
)
Phi
  • 414
  • 3
  • 7
  • Doesn't work with me. Why? I copy pasted your whole code. – neversaint Apr 06 '17 at 03:11
  • I had a few errors in the copied code, its now edited to work correctly. – Phi Apr 06 '17 at 04:05
  • Is there a way to keep the navbarPage in ui.R? logically it makes more sense. And I have a large navbarPage. – neversaint Apr 06 '17 at 04:20
  • yes, just take the `navbarPage()` portion and put it in your ui.R and the `observeEvent()` portion into server.R. – Phi Apr 06 '17 at 04:23
  • can you please give example code? In my earlier comment I meant navbarPage in either `ui.R` or `shinyUI()`. The latter being in one file app. – neversaint Apr 06 '17 at 04:28
  • Hard to read. It'll be really helpful if you can put it as edit in your post. Besides in your comment there I can't see the `shinyUI()` – neversaint Apr 06 '17 at 04:41
  • Doing it with your HTML centric way would be best of all solutions. But I get distortion of the navbar. See my update. Is there a way to fix that? – neversaint Apr 06 '17 at 07:06