2

I have a navbarMenu with a set of tabPanels that works fine (code block 1 below) but I want to make this dynamic so that I can add or remove tabPanels based on a condition at startup. Something along the lines of what I have in block 2 below (but that doesn't work). I'm seeing a couple of links to where people say this is not possible but it seems there must be a way. I actually only need to include or not include tabPanels on start up and don't need it to be truly dynamic.

I see an example that is close with a tabsetPanel : R Shiny - add tabPanel to tabsetPanel dynamically (with the use of renderUI). And here it says it's not possible: reactive tabPanel in a navbarMenu in Shiny

Block 1: works but not dynamic

library(shiny)
runApp(list(
  ui = navbarPage(

    tabPanel("a"

    ),
    tabPanel("b"),
    navbarMenu('g', 
                 tabPanel("c"),
                 tabPanel("d")
    )
  ),
  server = function(input, output, session){


  }
))

Block 2: I want something like this - this doesn't work

library(shiny)
runApp(list(
  ui = navbarPage(

    tabPanel("a"

    ),
    tabPanel("b"),
    navbarMenu('g', 
                 uiOutput('tabs')
    )
  ),
  server = function(input, output, session){

    output$tabs <- renderUI({

      listoftabs <- c("c", "d")
      lapply(listoftabs, tabPanel)

    })
  }
))

reactive tabPanel in a navbarMenu in Shiny

Community
  • 1
  • 1
ZRoss
  • 1,437
  • 1
  • 15
  • 32
  • You need to put `narbarMenu` inside your `renderUI`. You cannot simply add `tabPanel` to an existing `navbarMenu` or `tabsetPanel` (the example that works has `tabsetPanel` inside `renderUI`). – Xiongbing Jin Nov 03 '16 at 20:09
  • Have you tested this out? I've tested many different variations of this and none seem to work. Does navbarMenu work at all from within a renderUI? – ZRoss Nov 03 '16 at 20:32
  • Sorry `navbarMenu` wouldn't work. The reason is that `navbarMenu` is part of the `navbarPage`. When you put `navbarMenu` inside `navbarPage`, it generates two HTML elements: one for the menu link, the other for the actual panel `div`. When you use it with `renderUI`, you only get the panel `div`. If you want dynamics, you'll have to re-render the whole `navbarPage` – Xiongbing Jin Nov 03 '16 at 20:36
  • Re-rendering would not be good. Since this only matters on start up, I only need a mechanism at start up that basically says if(something) then include both tabPanel c and d, otherwise include just c. – ZRoss Nov 03 '16 at 20:43
  • If this condition is not user-entered, you can add `if/else` to your ui code to determine which elements show up. `navbarMenu('g', if (a == 1) { tabPanel("c") } else if (a == 2) { tabPanel("d") } )` – Xiongbing Jin Nov 03 '16 at 20:54

1 Answers1

0

The answer by @warmoverflow (thanks!) with ifelse could work with a very limited number of tabs but if the tab you want included or excluded is a middle tab it won't work properly given the commas. Here is a solution where I rewrote the navbarMenu function just slightly to allow you to drop a tab meeting a condition

library(shiny)
runApp(list(
  ui = navbarPage(

    tabPanel("a"

    ),
    tabPanel("b"),
    f('g', drop = ifelse(1==1, 2, 3), 
               tabPanel("first"),
               tabPanel("firstinside"),
               tabPanel("secondinside"),
               tabPanel("last")
      )
),
  server = function(input, output, session){


  }
))



f <- function (title, drop , ..., icon = NULL) 
{
    structure(list(title = title, tabs = list(...)[-drop], iconClass = shiny:::iconClass(icon)), 
        class = "shiny.navbarmenu")
}
ZRoss
  • 1,437
  • 1
  • 15
  • 32