Search code examples
javascriptrshinyshinydashboardshinyjs

R shinydashboard - show/hide multiple menuItems based on user input


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.


Solution

  • 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.


    enter image description here

    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", placeholder = "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!