Hide/show menuitem in Shiny - r

I want to hide and show a menuItem when a user check a box. I used useShinyjs() and renderMenu() function but once the menuItem is shown, I cannot hide it again by unchecking the box.
This is what I did :
library(shiny)
library(shinydashboard)
library(shinyjs)
header <- dashboardHeader(title = "my app")
sidebar <- dashboardSidebar(
sidebarMenu(id="menu",
menuItem("Tab 1",tabName = "tab1", icon = icon("question")),
menuItemOutput("another_tab"),
menuItem("Tab 2", tabName = "tab2", icon = icon("home"))
)
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "tab1",
useShinyjs(),
checkboxInput("somevalue", "Check me", FALSE)
)
)
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output) {
output$another_tab <- renderMenu({
if(input$somevalue == TRUE)
menuItem("My tab", tabName = "tab3", icon = icon("cogs"))
})
}
shinyApp(ui, server)
How can we hide the menuItem again ?

Another way to do it is
output$another_tab <- renderMenu({
if(input$somevalue == TRUE) {
menuItem("My tab", tabName = "tab3", icon = icon("cogs"))
}else shinyjs::hide(selector = "a[data-value='tab3']" )
})

You can create an empty menuItem():
server <- function(input, output) {
output$another_tab <- renderMenu({
if(input$somevalue == TRUE)
menuItem("My tab", tabName = "tab3", id="tab3", icon = icon("cogs"))
else
menuItem(NULL)
})
}

Related

Move from one menuItem to another usung actionButton() when the name of it can be changed in a shiny dashboard

I have the shiny app below in which I would like to set the name of the second menuItem() by typing in the textInput() of the first menuItem(). And then move to it by clicking an actionButton(). Also why the textOutput() I use is dispalyed under the icon and not next it like the first one?
## app.R ##
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(
),
dashboardSidebar(
collapsed = TRUE,
sidebarMenu(
id="inTabset",
menuItem("Workspace", tabName = "workspace", icon = icon("upload")),
menuItemOutput("tab2")
)
),
dashboardBody(
tabItems(
# First tab content
tabItem(tabName = "workspace",
fluidRow(
textInput("name", "", value = "Process model", placeholder = NULL),
actionButton("nextt","Next", icon("paper-plane")
)
)
)
),
tabItem(
tabName = "Process model",
)
)
)
server <- function(input, output,session) {
output$tab2 <- renderMenu({
menuItem(text = input$name, tabName = "Process model", icon = icon("diagram-project"))
})
observeEvent(input$nextt, {
updateTabItems(session, "inTabset", selected = "Process model")
})
output$tabtitle <- renderText({
if (input$name == "") {
"Process model"
} else {
paste(input$name)
}
})
observeEvent(input$nextt, {
updateTabItems(session, "inTabset", selected = "Process model")
})
}
shinyApp(ui, server)
To dynamically create and name a menuItem you could use renderMenu and menuItemOutput.
library(shinydashboard)
library(shiny)
ui <- dashboardPage(
dashboardHeader(title = "Basic dashboard"),
dashboardSidebar(
sidebarMenu(
id = "inTabset",
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItemOutput("tab2")
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "dashboard",
textInput("name", "Create a name for your process", value = "", placeholder = NULL),
actionButton("nextt", "Next")
),
tabItem(
tabName = "widgets"
)
)
)
)
server <- function(input, output, session) {
observeEvent(input$nextt, {
updateTabItems(session, "inTabset", selected = "widgets")
})
output$tab2 <- renderMenu({
menuItem(text = input$name, tabName = "widgets", icon = icon("th"))
})
output$tabtitle <- renderText({
if (input$name == "") {
"Name of process"
} else {
paste(input$name)
}
})
observeEvent(input$nextt, {
updateTabItems(session, "inTabset", selected = "widgets")
})
}
shinyApp(ui, server)

URI routing for shinydashboard using shiny.router

Suppose you have a simple shinydashboard which contains links created with menuItem and pages created with tabItems:
library(shiny)
library(shinydashboard)
skin <- Sys.getenv("DASHBOARD_SKIN")
skin <- tolower(skin)
skin <- "blue"
## ui.R ##
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Widgets", icon = icon("th"), tabName = "widgets",
badgeLabel = "new", badgeColor = "green")
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")
),
tabItem(tabName = "widgets",
h2("Widgets tab content")
)
)
)
# Put them together into a dashboardPage
ui<-dashboardPage(
dashboardHeader(title = "Simple tabs"),
sidebar,
body
)
server <- function(input, output) {
}
shinyApp(ui, server)
Is it possible to create permalinks for the pages? e.g. the home page (tabName == "dashboard") has a URL of 127.0.0.1:1234/home and the widgets page is at 127.0.0.1:1234/widgets?
It seems that shiny doesn't have URL routing out of the box. shiny.router seems to be a possible alternative but I've found no easy ways to do this with shinydashboard i.e. with the use of menuItem and tabItem. I'm trying to avoid rewriting the app's UI to use something which is more tightly integrated with shiny.router (e.g. shiny.semantic)
Is it possible to keep the above shinydashboard code while implementing permalinks to the various different pages?
Here is how to use the below approach with shiny's tabPanel() function.
Workarounds not using library(shiny.router):
Edit - Alternative using clientData$url_search and mode = "push" for updateQueryString to push a new history entry onto the browser's history stack:
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
header = dashboardHeader(title = "Simple tabs"),
sidebar = dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem(
"Dashboard",
tabName = "dashboard",
icon = icon("tachometer-alt")
),
menuItem(
"Widgets",
icon = icon("th"),
tabName = "widgets",
badgeLabel = "new",
badgeColor = "green"
)
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets",
h2("Widgets tab content"))
))
)
}
server <- function(input, output, session) {
# http://127.0.0.1:6172/?tab=dashboard
# http://127.0.0.1:6172/?tab=widgets
observeEvent(getQueryString(session)$tab, {
currentQueryString <- getQueryString(session)$tab # alternative: parseQueryString(session$clientData$url_search)$tab
if(is.null(input$sidebarID) || !is.null(currentQueryString) && currentQueryString != input$sidebarID){
freezeReactiveValue(input, "sidebarID")
updateTabItems(session, "sidebarID", selected = currentQueryString)
}
}, priority = 1)
observeEvent(input$sidebarID, {
currentQueryString <- getQueryString(session)$tab # alternative: parseQueryString(session$clientData$url_search)$tab
pushQueryString <- paste0("?tab=", input$sidebarID)
if(is.null(currentQueryString) || currentQueryString != input$sidebarID){
freezeReactiveValue(input, "sidebarID")
updateQueryString(pushQueryString, mode = "push", session)
}
}, priority = 0)
}
shinyApp(ui, server, enableBookmarking = "disable")
Another Edit - using url_hash (uri fragments):
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
header = dashboardHeader(title = "Simple tabs"),
sidebar = dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem(
"Dashboard",
tabName = "dashboard",
icon = icon("tachometer-alt")
),
menuItem(
"Widgets",
icon = icon("th"),
tabName = "widgets",
badgeLabel = "new",
badgeColor = "green"
)
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets",
h2("Widgets tab content"))
))
)
}
server <- function(input, output, session) {
observeEvent(input$sidebarID, {
# http://127.0.0.1:6172/#dashboard
# http://127.0.0.1:6172/#widgets
newURL <- paste0(
session$clientData$url_protocol,
"//",
session$clientData$url_hostname,
":",
session$clientData$url_port,
session$clientData$url_pathname,
"#",
input$sidebarID
)
updateQueryString(newURL, mode = "replace", session)
})
observe({
currentTab <- sub("#", "", session$clientData$url_hash)
if(!is.null(currentTab)){
updateTabItems(session, "sidebarID", selected = currentTab)
}
})
}
shinyApp(ui, server, enableBookmarking = "disable")
Edit - using url_search: Actually we can do the same without bookmarking using getQueryString and updateTabItems:
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
header = dashboardHeader(title = "Simple tabs"),
sidebar = dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem(
"Dashboard",
tabName = "dashboard",
icon = icon("tachometer-alt")
),
menuItem(
"Widgets",
icon = icon("th"),
tabName = "widgets",
badgeLabel = "new",
badgeColor = "green"
)
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets",
h2("Widgets tab content"))
))
)
}
server <- function(input, output, session) {
observeEvent(input$sidebarID, {
# http://127.0.0.1:6172/?tab=dashboard
# http://127.0.0.1:6172/?tab=widgets
newURL <- paste0(
session$clientData$url_protocol,
"//",
session$clientData$url_hostname,
":",
session$clientData$url_port,
session$clientData$url_pathname,
"?tab=",
input$sidebarID
)
updateQueryString(newURL, mode = "replace", session)
})
observe({
currentTab <- getQueryString(session)$tab # alternative: parseQueryString(session$clientData$url_search)$tab
if(!is.null(currentTab)){
updateTabItems(session, "sidebarID", selected = currentTab)
}
})
}
shinyApp(ui, server, enableBookmarking = "disable")
Using bookmarks:
Not sure if you are interested in a workaround like this, but you could use shiny's bookmarking and updateQueryString to achive a similar behaviour:
library(shiny)
library(shinydashboard)
ui <- function(request) {
dashboardPage(
header = dashboardHeader(title = "Simple tabs"),
sidebar = dashboardSidebar(
sidebarMenu(
id = "sidebarID",
menuItem(
"Dashboard",
tabName = "dashboard",
icon = icon("tachometer-alt")
),
menuItem(
"Widgets",
icon = icon("th"),
tabName = "widgets",
badgeLabel = "new",
badgeColor = "green"
)
)
),
body = dashboardBody(tabItems(
tabItem(tabName = "dashboard",
h2("Dashboard tab content")),
tabItem(tabName = "widgets",
h2("Widgets tab content"))
))
)
}
server <- function(input, output, session) {
bookmarkingWhitelist <- c("sidebarID")
observe({
setBookmarkExclude(setdiff(names(input), bookmarkingWhitelist))
})
observeEvent(input$sidebarID, {
# http://127.0.0.1:6172/?_inputs_&sidebarID=%22dashboard%22
# http://127.0.0.1:6172/?_inputs_&sidebarID=%22widgets%22
newURL <- paste0(
session$clientData$url_protocol,
"//",
session$clientData$url_hostname,
":",
session$clientData$url_port,
session$clientData$url_pathname,
"?_inputs_&sidebarID=%22",
input$sidebarID,
"%22"
)
updateQueryString(newURL,
mode = "replace",
session)
})
}
shinyApp(ui, server, enableBookmarking = "url")
Some related links:
https://rstudio.github.io/shinydashboard/behavior.html#bookmarking
https://shiny.rstudio.com/reference/shiny/1.7.0/session.html
It is possible to restore a session, locally, in a Shiny app if the inputs have been previously written in a RDS file?
shinyjs - setBookmarkExclude for delay IDs
https://github.com/rstudio/shiny/issues/3546

Show/hide menuItem in shinydashboard

I need a menuItem hidden, when the app is entered into. When a user chooses a certain value, the menuItem has to appear.
I have tried shinyjs functions hidden, and it hides a menuItem, but when using show or toggle, a menuItem doesn't appear.
I've found R shinydashboard - show/hide multiple menuItems based on user input
and came up with this
library(shiny)
library(shinydashboard)
library(shinyjs)
header <- dashboardHeader(title = "APP", titleWidth = 330)
sidebar <- dashboardSidebar(
sidebarMenu(id="tabs",
menuItem("",tabName="default"),
menuItem("Scenarios",tabName = "scenarios", icon = icon("flag")),
uiOutput("recOpt"),
menuItem("Simulation", tabName = "game", icon = icon("gamepad")),
menuItem("Actions", tabName = "actions", icon = icon("folder"),
menuSubItem("Save project", tabName = "save"),
menuSubItem("Open project", tabName = "open")
)
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "scenarios",
useShinyjs(),
radioButtons("radio", h3("Radio buttons"),
choices = list("Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3))
)
)
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output) {
output$recOpt <- renderUI({
if(input$radio == 2)
menuItem("Options", tabName = "recOpt", icon = icon("bell"),
menuSubItem("No option",tabName="RO_00"),
menuSubItem("Option 1",tabName="RO_01")
)
})
}
shinyApp(ui, server)
It works but the hidden/shown item is not aligned correcty, nor the encoding is correct.
Have any ideas how to make it better?
A little late, but anyway:
Check the shinydashboard capabilities on dynamic content.
This should do it:
library(shiny)
library(shinydashboard)
library(shinyjs)
header <- dashboardHeader(title = "APP", titleWidth = 330)
sidebar <- dashboardSidebar(
sidebarMenu(id="tabs",
menuItem("",tabName="default"),
menuItem("Scenarios",tabName = "scenarios", icon = icon("flag")),
menuItemOutput("recOpt"),
menuItem("Simulation", tabName = "game", icon = icon("gamepad")),
menuItem("Actions", tabName = "actions", icon = icon("folder"),
menuSubItem("Save project", tabName = "save"),
menuSubItem("Open project", tabName = "open")
)
)
)
body <- dashboardBody(
tabItems(
tabItem(tabName = "scenarios",
useShinyjs(),
radioButtons("radio", h3("Radio buttons"),
choices = list("Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3))
)
)
)
ui <- dashboardPage(header, sidebar, body)
server <- function(input, output) {
output$recOpt <- renderMenu({
if(input$radio == 2)
menuItem("Options", tabName = "recOpt", icon = icon("bell"),
menuSubItem("No option",tabName="RO_00"),
menuSubItem("Option 1",tabName="RO_01")
)
})
}
shinyApp(ui, server)

shinydashboard: menuSubItem not rendering at start in case of several menuSubItems

I found that menuSubItem content is not rendering in case of several (more than one) tabItems.
Minimal example demonstrating this behavior is below.
The desired behavior is to show content of the tabItem marked as selected = TRUE on startup. Now, the content shows up only after switching between menuSubItems in the sidebar.
How can I make it work?
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
uiOutput("body")
)
)
server <- function(input, output, session) {
output$menu <- renderMenu(
sidebarMenu(
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
output$body <- renderUI({
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
})
}
shinyApp(ui = ui, server = server)
Indeed, putting ui elements directly in UI solves it.
But the approach of putting everything inside ui is limited to situations that do not involve using reactive values. As I understand passing reactive value from server to ui is not possible in general (or limited to special cases). Please correct if I am wrong... Thanks
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
)
)
server <- function(input, output, session) {
output$menu <- renderMenu(
sidebarMenu(
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
}
shinyApp(ui = ui, server = server)
Renaming your output to something other than "body" helps - please see this.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "MINIMAL EXAMPLE"),
dashboardSidebar(
sidebarMenuOutput("menu")
),
dashboardBody(
uiOutput("myBodyOutput")
)
)
server <- function(input, output, session) {
output$myBodyOutput <- renderUI({
tabItems(
tabItem(tabName = "tab1",
h4("MY TEXT 1")
),
tabItem(tabName = "tab2",
h4("MY TEXT 2")
))
})
output$menu <- renderMenu(
sidebarMenu(id = "sidebarID",
menuItem(text = "TABS", tabName = "TABS", startExpanded = T,
menuSubItem(text = "tab1", tabName="tab1",
icon = icon("cube"), selected = TRUE),
menuSubItem(text = "tab2", tabName="tab2",
icon = icon("cube"), selected = FALSE)
)
)
)
}
shinyApp(ui = ui, server = server)

Home Button in Header in R shiny Dashboard

I am trying to add a home button in the header of my Shiny app so that whenever anyone clicks it from any tab, it will redirect to the first page. Currently I am using one actionButton in every tab with observeEvent to go back to first page.
I am not able to add any actionButton in the header section of Shiny app. Is there any way around for this feature?
It is something like this:
Sample Shiny Look
Reproducible Code:
library(shiny)
library(shinydashboard)
library(shinyjs)
options(shiny.maxRequestSize=1000*1024^2)
app <- shinyApp(
a <- dashboardPage(
dashboardHeader(title = "Sample Shiny", titleWidth=1450),
dashboardSidebar(sidebarMenu(id='tabs',
menuItem("Welcome", tabName = "welcome"),
menuItem("Tab1", tabName = "tab1"),
menuItem("Tab2",
menuSubItem("Tab2_1", tabName = "tab2_1"),
menuSubItem("Tab2_2", tabName = "tab2_2"))
)
),
dashboardBody( shinyjs::useShinyjs(),
tabItems(
tabItem(tabName="welcome", tabPanel(title = "Score",fluidRow(valueBoxOutput("box_01"),valueBoxOutput("box_02")))),
# First tab content
tabItem(tabName = "tab1",actionButton("homeButton1", "Home")),
# Second tab content
tabItem(tabName = "tab2_1",tabsetPanel(id = "test",tabPanel(title = "tab2_1",actionButton("homeButton2", "Home"),actionButton("NextButton2", "Tab3")))),
tabItem(tabName = "tab2_2",tabsetPanel(id = "outputTabset",tabPanel(title = "Tab 3",actionButton("homeButton3", "Home"))))
)
)),
b<-shinyServer(function(input, output, session) {
##########Links from first page
output$box_01 <- renderValueBox({
box1<-valueBox(value=01,
icon = icon("database",lib="font-awesome")
,width=NULL
,color = "blue"
,href="#"
,subtitle=HTML("<b>Tab 1</b>")
)
box1$children[[1]]$attribs$class<-"action-button"
box1$children[[1]]$attribs$id<-"button_box_01"
return(box1)
})
output$box_02 <- renderValueBox({
box2<-valueBox(value=02,
icon = icon("user-secret",lib="font-awesome")
,width=NULL
,color = "yellow"
,href="#"
,subtitle=HTML("<b>Tab 2</b>")
)
box2$children[[1]]$attribs$class<-"action-button"
box2$children[[1]]$attribs$id<-"button_box_02"
return(box2)
})
observeEvent(input$button_box_01,{
if(input$button_box_01[1]>0){
newtab <- switch(input$tabs,
"welcome" = "tab1",
"tab1" = "welcome"
)
updateTabItems(session, "tabs", newtab)
} })
observeEvent(input$button_box_02,{
if(input$button_box_02[1]>0){
newtab <- switch(input$tabs,
"welcome" = "tab2_1",
"tab2_1" = "welcome"
)
updateTabItems(session, "tabs", newtab)
} })
### HomeButtons
observeEvent(input$homeButton1,{
newtab <- switch(input$tabs,
"welcome" = "tab1",
"tab1" = "welcome"
)
updateTabItems(session, "tabs", newtab)
})
observeEvent(input$homeButton2,{
newtab <- switch(input$tabs,
"welcome" = "tab2_1",
"tab2_1" = "welcome"
)
updateTabItems(session, "tabs", newtab)
})
observeEvent(input$NextButton2,{
newtab <- switch(input$tabs,
"tab2_2" = "tab2_1",
"tab2_1" = "tab2_2"
)
updateTabItems(session, "tabs", newtab)
})
observeEvent(input$homeButton3,{
newtab <- switch(input$tabs,
"welcome" = "tab2_2",
"tab2_2" = "welcome"
)
updateTabItems(session, "tabs", newtab)
})
#######SideBar Disable
addClass(selector = "body", class = "sidebar-collapse")
})
)
shiny::runApp(app,launch.browser=TRUE,host="0.0.0.0",port=6105)
See the following solution. You need to style the position with CSS, still. Key is to put the actionButton into the header with tags$li(class = "dropdown", ...), otherwise dashboardHeader will not accept it:
ui <- dashboardPage(
dashboardHeader(title = "Demo", tags$li(class = "dropdown", actionButton("home", "Home"))),
dashboardSidebar(sidebarMenu(id = "sidebar", # id important for updateTabItems
menuItem("Home", tabName = "home", icon = icon("house")),
menuItem("Tab1", tabName = "tab1", icon = icon("table")),
menuItem("Tab2", tabName = "tab2", icon = icon("line-chart")),
menuItem("Tab3", tabName = "tab3", icon = icon("line-chart")))
),
dashboardBody(
tabItems(
tabItem("home", "This is the home tab"),
tabItem("tab1", "This is Tab1"),
tabItem("tab2", "This is Tab2"),
tabItem("tab3", "This is Tab3")
))
)
server = function(input, output, session){
observeEvent(input$home, {
updateTabItems(session, "sidebar", "home")
})
}
shinyApp(ui, server)
Here's an option using javascript and a home icon which fits into the header nicely:
dashboardHeader(title = "Your Title",
tags$li(a(onclick = "openTab('home')",
href = NULL,
icon("home"),
title = "Homepage",
style = "cursor: pointer;"),
class = "dropdown",
tags$script(HTML("
var openTab = function(tabName){
$('a', $('.sidebar')).each(function() {
if(this.getAttribute('data-value') == tabName) {
this.click()
};
});
}")))
)
Change home in the openTab('home') part to whatever your home tab is called and it will switch to that tab when clicked.

Resources