4

I am creating my app where I want to hide particular menuItem and its contains depending upon user credential. I want to show everything for admin/tester but not all user. I found question in stack overflow, Hide an element (box/tabs) in shiny dashbaord, I am modified code as below

library(shiny)
library(shinydashboard)
library(shinyjs)

ui <- dashboardPage(

dashboardHeader(title = "Set")
,dashboardSidebar(
   sidebarSearchForm(label = "Search...", "searchText", "searchButton"),
  sidebarMenu(
    menuItem("Port", tabName = "P", icon = icon("cog"))
    ,menuItem("Rank", tabName = "Rank", icon = icon("cog"))
    ,menuItem("Mark", tabName = "Mark", icon = icon("bar-chart"))
    ,menuItem("Read", tabName = "Read", icon = icon("file-pdf-o"))
    ,useShinyjs()
    ,menuItem("Port, tabName = "Ocean", icon = icon("heart"))
  )
  ,uiOutput('Super')
  ,uiOutput('AList')
  ,uiOutput('BList')
  ,uiOutput('DList')
  ,uiOutput('SList')
)


,dashboardBody(
....
)
)

server <- shinyServer(function(input, output, session) {
  observeEvent(session$user,{
   if (session$user == "tester") return(NULL)
     hide(id = "Port", anim = TRUE)
 })
}

shinyApp(ui = ui, server = server) 

However, it is not working, Any tips ?

Community
  • 1
  • 1
Kush Patel
  • 3,685
  • 5
  • 42
  • 65
  • 1
    Well, you are at least missing `"` after `"Port` you could also provide minimal working example(without `....`). Would help debugging. – Mikael Jumppanen Apr 12 '16 at 08:43

1 Answers1

8

So, your approach has one problem: The way that the menuItems look like in the final document.

The code you provided is saying: Hide the element with Id "Port"! This would all be fine, if the menuItems actually had an Id, but when you look at them (right click + inspect) you'd see that's not the case.

Close inspection shows, that your menuItems can be identified in the document by tag name (= a) and the data-value (which correponds to the assigned tabName). This is the selecting argument for your hiding command. I don't know if Shinyjs offers searching by other attributes, but you might as well write the JS code youself.

In the code below, I faked the user login with a textInput. You can observe, that the first menuItem only shows, if you insert "tester" into the text field.

The way it's done: You send a message to the client to show/hide an item with certain tabName. The JS script searches through all a tags for the one with your given name stored in its data-value attribute. Hiding is done by display: none.

library(shiny)
library(shinydashboard)

ui <- dashboardPage(
  dashboardHeader(title = "Set"),
  dashboardSidebar(
    sidebarSearchForm(label = "Search...", "searchText", "searchButton"),
    tags$head(tags$script(HTML("
      Shiny.addCustomMessageHandler('manipulateMenuItem', function(message){
        var aNodeList = document.getElementsByTagName('a');

        for (var i = 0; i < aNodeList.length; i++) {
          if(aNodeList[i].getAttribute('data-value') == message.tabName) {
            if(message.action == 'hide'){
              aNodeList[i].setAttribute('style', 'display: none;');
            } else {
              aNodeList[i].setAttribute('style', 'display: block;');
            };
          };
        }
      });
    "))),
    sidebarMenu(
      menuItem("Port", tabName = "P", icon = icon("cog")),
      menuItem("Rank", tabName = "Rank", icon = icon("cog")),
      menuItem("Mark", tabName = "Mark", icon = icon("bar-chart")),
      menuItem("Read", tabName = "Read", icon = icon("file-pdf-o")),
      menuItem("Port", tabName = "Ocean", icon = icon("heart"))
    ),
    uiOutput('Super'),
    uiOutput('AList'),
    uiOutput('BList'),
    uiOutput('DList'),
    uiOutput('SList')
  ),
  dashboardBody(
    textInput("user", "User ID fake.")
  )
)

server <- function(input, output, session) {
  observeEvent(input$user,{
    if(input$user != "tester"){
      session$sendCustomMessage(type = "manipulateMenuItem", message = list(action = "hide", tabName = "P"))
    }else{
      session$sendCustomMessage(type = "manipulateMenuItem", message = list(action = "show", tabName = "P"))
    }
 })
}

shinyApp(ui, server)
K. Rohde
  • 9,439
  • 1
  • 31
  • 51
  • 1
    By the way, `shinyjs` does let you select by any valid CSS selector, not only by id. Just use the `selector` argument (eg. `shinyjs::hide(selector = "a[data-value=='P']")`) – DeanAttali Apr 17 '16 at 22:50
  • @K. Rohde this is great , how can i tweak you code to hide more than one tabName, i tried `server <- function(input, output, session) { observeEvent(input$user,{ if(input$user != "tester"){ session$sendCustomMessage(type = "manipulateMenuItem", message = list(action = "hide", tabName = c("Rank","Read")) }else{ session$sendCustomMessage(type = "manipulateMenuItem", message = list(action = "show", tabName = c("Rank","Read"))) } }) }` but somehow its not working. – PSraj Nov 10 '16 at 08:57
  • @PSraj Hey, sorry for this late answer. In the JS code, I checked if the tab is exactly the given one in the "manipulateMenuItem" function. If you want to send a list of tabs to hide/show, you'll have to change the JS code. I'd add another for loop to go through all message.tabName items. (`for(var j = 0; j++, j < message.tabName.length) { ... }`) – K. Rohde Nov 20 '16 at 13:08
  • 2
    @DeanAttali There is a small type in your `shinyjs` code. You should use a single `=` instead of `==`. Just to share, if somebody wants to use the `shinyjs` solution: `shinyjs::hide(selector = "a[data-value='P']"` – thothal Dec 04 '17 at 08:31
  • 2
    @thothal thank you, that's correct, just a single `=` in the javascript equality – DeanAttali Dec 04 '17 at 17:46