Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Get id's of selected menuItem and notificationItem #114

Closed
metanoid opened this issue Dec 22, 2015 · 5 comments
Closed

Comments

@metanoid
Copy link

metanoid commented Dec 22, 2015

I mostly want this for notificationItems, but in crafting a minimal example I noticed that I couldn't actually get this for menuItems either. The basic idea is that when a user clicks on a specific notificationItem, I want to get which notificationItem was clicked, and do something based on that (e.g. change a DataTable to show data relevant to that notification). I can't find any way of getting that information. Here's an example:
ui.R

dashboardPage(
  dashboardHeader(dropdownMenuOutput("dropdownmenu")),
  dashboardSidebar(sidebarMenuOutput("sidebarmenu")),
  dashboardBody(tabItems(tabItem(tabName = "mytab",
                        textOutput("notificationoutput"),
                        textOutput("sidebaroutput"))))
)

server.R

server = shinyServer(function(input, output, session){
  output$dropdownmenu = renderMenu({
    dropdownMenu(type = "notifications", badgeStatus = "warning",
                 notificationItem(icon = icon("users"), status = "info",
                                  "5 new members joined today"
                 ),
                 notificationItem(icon = icon("warning"), status = "danger",
                                  "Resource usage near limit."
                 ),
                 notificationItem(icon = icon("shopping-cart", lib = "glyphicon"),
                                  status = "success", "25 sales made"
                 ),
                 notificationItem(icon = icon("user", lib = "glyphicon"),
                                  status = "danger", "You changed your username"
                 )
    )
  })
  output$sidebarmenu = renderMenu({
    sidebarMenu(menuItem("5 new members joined today",icon = icon("users"), tabName = "mytab"),
                menuItem("Resource usage near limit.",icon = icon("warning"), tabName = "mytab"),
                menuItem("25 sales made",icon = icon("shopping-cart", lib = "glyphicon"), tabName = "mytab"),
                menuItem("You changed your username",icon = icon("user", lib = "glyphicon"), tabName = "mytab"), 
                id = "mysidebar"
    )
  })
  output$notificationoutput = renderText({
    if(is.null(input$dropdownmenu)){
      notificationitemid = "a"
    }else{
      notificationitemid = input$dropdownmenu 
    }
    return(notificationitemid)
  })
  output$sidebaroutput = renderText({
    if(is.null(input$mysidebar)){
      sidebaritemid = "b"
    }else{
      sidebaritemid = input$mysidebar 
    }
    return(sidebaritemid)
  })

})

What I would like is for the values "a" and "b" to be updated when the user clicks on a notificationItem or menuItem. According to the documentation for ?sidebarMenu, this should already be happening, so maybe that's a bug?

@metanoid
Copy link
Author

Workaround found by stackoverflow user Batanichek: see here

@glfeng318
Copy link

add a id parameter to menuItem function, then we can use shinyjs's function onclick to update the clicked message as read with R code.

@metanoid
Copy link
Author

@Funnng I can't seem to figure out how to do that. I've made a pull request to get the id's as arguments to the menuItem function here

If there is a better way to do this please let me know. I have very little confidence in what I am doing here.

@wch
Copy link
Contributor

wch commented Feb 24, 2017

It's already possible to find the currently-selected menuItem or subMenuItem, if the sidebarMenu has an id, and the menuItem/subMenuItem have a tabName.

However, it isn't currently possible to get the currently selected notificationItem. It might make sense to add an ID to the dropdownMenu and set an input value with that ID.

@bborgesr bborgesr mentioned this issue Apr 25, 2017
@bborgesr
Copy link
Contributor

Here's where we're at right now:

  • As Winston said above, it isn't currently possible to get the currently selected notificationItem() (or, for that matter, messageItem() or taskItem()). It might make sense to add an id param to the dropdownMenu() function and set a Shiny input with that id. To get this working properly (and play nice with bookmarking, document, etc.) is a reasonable amount of work, so we're not doing it for the upcoming release (May 2017). I opened another issue targeted specifically at this, with some ideas of what we'd want to do for that feature: Make dropdownMenu a Shiny input if an id is provided #208

  • As Winston also said, it's already possible to find the currently-selected menuItem() or menuSubItem(), if the sidebarMenu() has an id, and the menuItem()/menuSubItem() has a tabName.

    Here's an example (click on the arrow to show the code).

    Notice that no tabItems( tabItem(), tabItem(), ... ) is used in this app, even though all childless menuItem()s and menuSubItem()s have a tabName argument.

    library(shiny)
    library(shinydashboard)
    
    ui <- dashboardPage(
      dashboardHeader(), 
      dashboardSidebar(
        sidebarMenu(
          # Setting id makes input$tabs give the tabName of currently-selected tab
          id = "tabs",
          
          menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
          menuItem("Widgets", icon = icon("th"), tabName = "widgets", badgeLabel = "new"),
          menuItem("Charts", icon = icon("bar-chart-o"),
            menuSubItem("Sub-item 1", tabName = "subitem1"),
            menuSubItem("Sub-item 2", tabName = "subitem2")
          )
        )
      ),
      dashboardBody(
        textOutput("res")
      )
    )
    
    server <- function(input, output, session) {
      output$res <- renderText({
        paste("You've selected:", input$tabs)
      })
    }
    
    shinyApp(ui, server)

    Caveats:

    • As mentioned, sidebarMenu() must take in an id. For example if you pass in id = "tabs", then, anywhere in the server function, you can know which menuItem() (or menuSubItem()) is selected by accessing input$tabs.

    • Childless menuItem()s (and menuSubItem()s) v childfull menuItem()s behave differently and there's different arguments that apply to either:

      • Childless menuItem()s/menuSubItem()s must be given a tabName param; in addition, one of these can have selected = TRUE, which lets Shiny know that you want input$tabs to start out this that item's tabName on app startup (if you specified a tabItem() for that tabName, that will what you first see in the dashboard body when you launch your app).
      • "Childfull" menuItem()s cannot have a tabName or a selected argument (or rather, they can, but this will be completely ignored by Shiny). Instead (and once Updates #199 is merged), at most, one of them can take a startExpanded = TRUE, which tells Shiny to start up with that menuItem() expanded, i.e. revealing all its children. (The reason that, at most, only one childfull menuItem() can start expanded is because in general in AdminLTE, only one thing can be expanded in the sidebar at any one time). In alternative to tabName, you can pass in an expandedName, which is how Shiny lets you know which (if any) menuItem() is currently expanded (more on that below, and note that this also required Updates #199 to have been merged).
    • This last one is more of a bonus (!!) than a caveat, but oh well...
      Once Updates #199 is merged, you also get a couple of other things "for free" (no need to add an id or anything, like above):

      • There's an automatic way to access which childfull menuItem() (if any) is currently expanded. Anywhere on your server function use input$sidebarItemExpanded to get the expandedName of the currently expanded menuItem() (or NULL is none is currently expanded). (Don't worry: even if you don't pass in an expandedName, Shiny has a sensible default -- it will construct one for you by taking the mandatory text argument you passed and removing all white space.) You can use input$sidebarItemExpanded as any other input, including making other UI elements conditional on it. And the cherry on top: since you get this input "for free," you also get bookmarking of this input "for free." (I.e. the bookmarked URL will capture which, if any, menuItem() was expanded and on restore, it will expand the same).

      • Similarly, there is also an automatic way to access whether the whole sidebar is expanded or collapsed at the moment. Use input$sidebarCollapsed to know if the sidebar is collapsed ("true") or expanded ("false"). While this may seem less interesting than the former, it is mostly useful for bookmarking. (I.e. the bookmarked URL will capture whether the sidebar is collapsed or expanded and, on restore, it will have the same value and look).


So, TLDR:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants