The idea is to have a user input (access code), based on which different menuItems can be accessed. So basically we have a custom version of app available based on user's requirement.
A working example for 3 menuItems is as follow:
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "SHOW/HIDE MULTIPLE MENU ITEMS"),
dashboardSidebar(
useShinyjs(),
sidebarMenu(
id = "tabs",
hidden(
menuItem("MENU ITEM 1", tabName = "mi1"),
menuItem("MENU ITEM 2", tabName = "mi2"),
menuItem("MENU ITEM 3", tabName = "mi3")
),
textInput(inputId = "accessToken", label = "Access Code", value = "Show/Hide Menu Items.")
)
),
dashboardBody()
)
server <- function (input, output, session){
observeEvent(input$accessToken,{
if(input$accessToken == "001"){
hide(selector = "ul li:eq(0)")
hide(selector = "ul li:eq(1)")
show(selector = "ul li:eq(2)")
} else if (input$accessToken == "010"){
hide(selector = "ul li:eq(0)")
show(selector = "ul li:eq(1)")
hide(selector = "ul li:eq(2)")
} else if (input$accessToken == "011"){
hide(selector = "ul li:eq(0)")
show(selector = "ul li:eq(1)")
show(selector = "ul li:eq(2)")
} else if (input$accessToken == "100"){
show(selector = "ul li:eq(0)")
hide(selector = "ul li:eq(1)")
hide(selector = "ul li:eq(2)")
} else if (input$accessToken == "101"){
show(selector = "ul li:eq(0)")
hide(selector = "ul li:eq(1)")
show(selector = "ul li:eq(2)")
} else if (input$accessToken == "110"){
show(selector = "ul li:eq(0)")
show(selector = "ul li:eq(1)")
hide(selector = "ul li:eq(2)")
} else if (input$accessToken == "111"){
show(selector = "ul li:eq(0)")
show(selector = "ul li:eq(1)")
show(selector = "ul li:eq(2)")
} else{
hide(selector = "ul li")
}
})
}
shinyApp(ui, server)
This works perfectly fine with all combinations of 3 menuItems visible for a unique access code.
BUT as you can see this is a lot of repetitive code for accessing 3 menuItems.
In actual I have 10 or even higher number of menuItems, so overall the number of if else statements are going to increase exponentially.
WHAT I HAVE TRIED:
I thought about this logic: For 10 menuItems, have an access code of 10 digits, where each digit can have a value 0 (hide) or 1 (show).
observeEvent(input$accessToken, {
tokenStr <- input$accessToken
tokenStrShow <- which(strsplit(tokenStr, "")[[1]]=="1")
tokenStrHide <- which(strsplit(tokenStr, "")[[1]]=="0")
for (i in tokenStrShow){
# some logic to show all menuItems with value 1
# FOLLOWING DOESNOT WORK
# paste0("show(selector='ul li:eq(",i,")'")
}
})
I also came across THIS javascript logic which I am trying to implement. But I do not know how to do it in Shiny.
Here is an idea for growing your sidebarMenu
dynamically using renderUI
and uiOutput
. It is also fairly straightforward to convert to a for loop if your number of tabs grows.
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "SHOW/HIDE MULTIPLE MENU ITEMS"),
dashboardSidebar(
useShinyjs(),
uiOutput('sidebar'),
textInput(inputId = "accessToken", label = "Access Code", value = "Show/Hide Menu Items.")
),
dashboardBody()
)
server <- function (input, output, session){
output$sidebar <- renderUI({
menu_items = list()
if(substr(input$accessToken,1,1)=='1')
menu_items[[length(menu_items)+1]] = menuItem("MENU ITEM 1", tabName = "mi1")
if(substr(input$accessToken,2,2)=='1')
menu_items[[length(menu_items)+1]] = menuItem("MENU ITEM 2", tabName = "mi2")
if(substr(input$accessToken,3,3)=='1')
menu_items[[length(menu_items)+1]] = menuItem("MENU ITEM 3", tabName = "mi3")
print(menu_items)
sidebarMenu(id = "tabs",menu_items)
})
}
shinyApp(ui, server)
Hope this helps!
This is for future readers.
Florian answer was helpful but since I wanted to keep my menuItem
s in dashboardSidebar
.
I spent some more time and realized I was using the paste0
incorrectly.
I ended up using the following:
observeEvent(input$accessToken, {
tokenStr <- strsplit(input$accessToken, "")[[1]]
tokenLen <- length(tokenStr)
if(tokenLen == 3){
tokenStrShow <- which(tokenStr=="1")
tokenStrHide <- which(tokenStr=="0")
for (i in tokenStrShow){
show(selector= paste0("ul li:eq(",i - 1,")"))
}
for (i in tokenStrHide){
hide(selector= paste0("ul li:eq(",i - 1,")"))
}
}
})
The advantages of this method were:
- I was able to keep my dashboardSidebar as it is. (This was needed for my project)
- Easily extendable for an increasing number of menuItems. ( only requires editing
tokenLen
来源:https://stackoverflow.com/questions/51946319/r-shinydashboard-show-hide-multiple-menuitems-based-on-user-input