Usage of Uioutput in Multiple Menuitems in R Shiny Dashboard

Usage of UIOutput in multiple menuItems in R shiny dashboard

You could create a dummy tabItem which is hidden and select that bu default. This will give the illusion that no tabItem is selected. To hide the tabItem option you could use hidden function from shinyjs package.

Following is the modified ui code:

ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
shinyjs::useShinyjs(),
id = "tabs",
menuItem("Charts", icon = icon("bar-chart-o"),
shinyjs::hidden(menuSubItem("dummy", tabName = "dummy")),
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2"),
menuSubItem("Sub-item 3", tabName = "subitem3")
))),
dashboardBody(
tabItems(tabItem("dummy"),
tabItem("subitem1", uiOutput("brand_selector")),
tabItem("subitem2", 4),
tabItem("subitem3", 7))
))

EDIT1:
As per the comments and reference from the answers given bu Joe here you can do that as follows:

candyData <- read.table(
text = "
Brand Candy value
Nestle 100Grand Choc1
Netle Butterfinger Choc2
Nestle Crunch Choc2
Hershey's KitKat Choc4
Hershey's Reeses Choc3
Hershey's Mounds Choc2
Mars Snickers Choc5
Nestle 100Grand Choc3
Nestle Crunch Choc4
Hershey's KitKat Choc5
Hershey's Reeses Choc2
Hershey's Mounds Choc1
Mars Twix Choc3
Mars Vaid Choc2",
header = TRUE,
stringsAsFactors = FALSE)
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
shinyjs::useShinyjs(),
id = "tabs",
menuItem("Charts", icon = icon("bar-chart-o"),
shinyjs::hidden(menuSubItem("dummy", tabName = "dummy")),
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2"),
menuSubItem("Sub-item 3", tabName = "subitem3")
))),
dashboardBody(
tabItems(tabItem("dummy"),
tabItem("subitem1", uiOutput("brand_selector")),
tabItem("subitem2", uiOutput("brand_selector1")),
tabItem("subitem3", uiOutput("brand_selector2")))
))
server <- function(input, output,session) {

observeEvent(input$Select1,{
updateSelectInput(session,'Select2',

choices=unique(candyData$Candy[candyData$Brand==input$Select1]))
})
observeEvent(input$Select2,{
updateSelectInput(session,'Select3',

choices=unique(candyData$value[candyData$Brand==input$Select1 &
candyData$Candy==input$Select2]))
})
output$brand_selector1 <- output$brand_selector2 <- output$brand_selector <- renderUI({
box(title = "Data", status = "primary", solidHeader = T, width = 12,
fluidPage(
fluidRow(

column(2,offset = 0, style='padding:1px;',
selectInput("Select1","select1",unique(candyData$Brand))),
column(2,offset = 0,
style='padding:1px;',selectInput("Select2","select2",choices = NULL)),
column(2, offset = 0,
style='padding:1px;',selectInput("Select3","select3",choices=NULL ))
)))
})}
shinyApp(ui = ui, server = server)

EDIT2:

Here is a slightly different approach without using renderUI and using shinyModule:

candyData <- read.table(
text = "
Brand Candy value
Nestle 100Grand Choc1
Netle Butterfinger Choc2
Nestle Crunch Choc2
Hershey's KitKat Choc4
Hershey's Reeses Choc3
Hershey's Mounds Choc2
Mars Snickers Choc5
Nestle 100Grand Choc3
Nestle Crunch Choc4
Hershey's KitKat Choc5
Hershey's Reeses Choc2
Hershey's Mounds Choc1
Mars Twix Choc3
Mars Vaid Choc2",
header = TRUE,
stringsAsFactors = FALSE)
library(shiny)
library(shinydashboard)

submenuUI <- function(id) {
ns <- NS(id)
tagList(
box(title = "Data", status = "primary", solidHeader = T, width = 12,
fluidPage(
fluidRow(

column(2,offset = 0, style='padding:1px;',
selectInput(ns("Select1"),"select1",unique(candyData$Brand))),
column(2,offset = 0,
style='padding:1px;',selectInput(ns("Select2"),"select2",choices = NULL)),
column(2, offset = 0,
style='padding:1px;',selectInput(ns("Select3"),"select3",choices=NULL ))
)))
)

}

# submenu <- function(input,output,session){}
submenuServ <- function(input, output, session){

observeEvent(input$Select1,{
updateSelectInput(session,'Select2',

choices=unique(candyData$Candy[candyData$Brand==input$Select1]))
})
observeEvent(input$Select2,{
updateSelectInput(session,'Select3',

choices=unique(candyData$value[candyData$Brand==input$Select1 &
candyData$Candy==input$Select2]))
})

}

ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
shinyjs::useShinyjs(),
id = "tabs",
menuItem("Charts", icon = icon("bar-chart-o"),
shinyjs::hidden(menuSubItem("dummy", tabName = "dummy")),
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2"),
menuSubItem("Sub-item 3", tabName = "subitem3")
))),
dashboardBody(
tabItems(tabItem("dummy"),
tabItem("subitem1", submenuUI('submenu1')),
tabItem("subitem2", submenuUI('submenu2')),
tabItem("subitem3", submenuUI('submenu3'))
)
))
server <- function(input, output,session) {

callModule(submenuServ,"submenu1")
callModule(submenuServ,"submenu2")
callModule(submenuServ,"submenu3")

}
shinyApp(ui = ui, server = server)

Hope it helps!

Shiny Dashboard: Render multiple menu items and output dynamic content to each

Answering my own question, but feel free to jump in if you have something more elegant.

I think my initial understanding of shiny dashboard is wrong, causing the app structure to be invalid.

The trick here is to add id to the sidebarMenu, so that page focus could be tracked and parsed later. Then each of the render function will listen on the input and render associated content.

shinyApp(
ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "sidebar_menu",
menuItemOutput("dynamic_menu"),
menuItem("Menu2", tabName = "menu2")
)
),
dashboardBody(
uiOutput("menu1_content"),
uiOutput("menu2_content")
),
title = "Example"
),
server = function(input, output, session) {
output$dynamic_menu <- renderMenu({
menu_list <- lapply(letters[1:5], function(x) {
menuSubItem(x, tabName = paste0("menu1-", x))
})
menuItem(
text = "Menu1",
startExpanded = TRUE,
do.call(tagList, menu_list)
)
})

output$menu1_content <- renderUI({
sidebar_menu <- tstrsplit(input$sidebar_menu, "-")
if (sidebar_menu[[1]] == "menu1") box(sidebar_menu[[2]])
})

output$menu2_content <- renderUI({
sidebar_menu <- tstrsplit(input$sidebar_menu, "-")
if (sidebar_menu[[1]] == "menu2") box("I am menu2")
})
}
)

Using similar UI script in R shiny under multiple subMenuItems

Your code can be rewritten with shiny modules. The UI module where you want to display the two dropdowns can be written as one (Ui function) and then can be referred in the places you want.

Modified code:

library(shiny)
library(shinydashboard)

submenuUI <- function(id) {
ns <- NS(id)

# return a list of tags
tagList(
column(2,offset = 0, style='padding:1px;',
selectInput(ns("select1"),"select1",c("A1","A2","A3"), selected = "A1")),
column(2,offset = 0, style='padding:1px;',
selectInput(ns("select2"),"select2",c("A3","A4","A5"), selected = "A3"))
)

}

submenu <- function(input,output,session){}

ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(

id = "tabs",
menuItem("Charts", icon = icon("bar-chart-o"),
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2"),
menuSubItem("Sub-item 3", tabName = "subitem3"),
menuSubItem("Sub-item 4", tabName = "subitem4")
))),
dashboardBody(
tabItems(tabItem("subitem1", submenuUI('submenu1')),
tabItem("subitem2", submenuUI('submenu2')),
tabItem("subitem3", submenuUI('submenu3')),
tabItem("subitem4", "Sub-item 2 tab content"))))
server <- function(input, output, session) {
callModule(submenu, "submenu")
}
shinyApp(ui, server)

Can you use uiOutput in a shiny Dashboard?

Once you correct the typo the following works for me. You should be able to use uiOuput.

library(shinydashboard)
runApp(
list(ui = dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem(uiOutput("Symbols"))
)
),
dashboardBody()
)

, server = function(input, output) {

output$Symbols<-renderUI({
selectInput('Test', 'Test:', choices = c(1,2,3), selected = 1)
})
}
)
)

Using uiOutput in menuSubItem of shinydashboard

The issue got rectified by explicitly specifying the tab name of each menuSubItem as follows:

# Create dashboard sidebar
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem(text="test1", tabName="test1",
menuSubItem(icon=NULL, tabName="test1", selectInput("x", "X", c("a", "b", "c"), selected="a")),
menuSubItem(icon=NULL, tabName="test1", uiOutput("y"))
)
)
)

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

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.



Sample Image

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!

Using shiny plotOutput in multiple places in R

This is the modularized code for multiple plotting: Very similar to the selectInput one.

library(shiny)
library(shinydashboard)

plotopUI <- function(id) {
ns <- NS(id)

# return a list of tags
tagList(
plotOutput(ns('plt'))
)

}

plotop <- function(input,output,session){
ns <- session$ns

output$plt <- renderPlot({
plot(iris$Sepal.Length)
})
}

ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(

id = "tabs",
menuItem("Charts", icon = icon("bar-chart-o"),
menuSubItem("Sub-item 1", tabName = "subitem1"),
menuSubItem("Sub-item 2", tabName = "subitem2")
))),
dashboardBody(
tabItems(tabItem("subitem1", plotopUI('plt1')),
tabItem("subitem2", plotopUI('plt2')))))

server <- function(input, output, session) {
callModule(plotop, "plt1")
callModule(plotop, "plt2")
}
shinyApp(ui, server)

Shiny: Output will be shown in every menuItem

You aren't using tabName correctly. First, you shouldn't reuse tab names in the sidebar. Those will be clashing. A lot of your menuSubItem tabs are have repeated values. That should be fixed to something like...

sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Test1", tabName = "dashboard", icon = icon("dashboard")),
menuItem("Test2",tabName = "charts", icon = icon("bar-chart-o"),
menuSubItem("TTest1", tabName = "subitem1"),
menuSubItem("TTest2", tabName = "subitem2"),
menuSubItem("TTest3", tabName = "subitem3"),
menuSubItem("TTest4", tabName = "subitem4")),
menuItem("Test3", tabName = "choice", icon = icon("dashboard"),
menuSubItem("TTTest1", tabName = "subitem4"),
menuSubItem("TTTest2", tabName = "subitem5"),
menuSubItem("TTTest3", tabName = "subitem6"),
menuSubItem("TTTest4", tabName = "subitem7")),
menuItem("Test4", tabName = "Prod", icon = icon("dashboard"),
menuSubItem("TTTTest1", tabName = "subitem8"),
menuSubItem("TTTTest2", tabName = "subitem9"),
menuSubItem("TTTTest3", tabName = "subitem10"),
menuSubItem("TTTTest4", tabName = "subitem11"))

)
)

Notice now there are no repeated tabNames. These are what you want to use in the dashBoardBody to associate the sidebar with the body of the app.

If you want your leaflet map to appear in Test3/TTTest1, you need to use that tabName specifically. In the code chunk above, tabName = "subitem4".

 body <- dashboardBody(

tabItems(
# Map Output
tabItem(tabName = "subitem4",
fluidRow(
leafletOutput("myMap"),

tabBox(
title = "Legend",
id = "tabset1", height = "150px", width = "500px",
tabPanel("Explaining", "If this then that"),
tabPanel("Source", "Here you can find my data")
),

)
),

The connection between your sidebar menu and what appears on the body of those pages is the tabName.

R shiny: multiple use in ui of same renderUI in server?

You can't (shouldn't) have two elements with the same ID in an HTML document (whether using Shiny or not). Certainly when using Shiny having multiple elements with the same ID will be problematic. I would also subjectively vote that you could substantially improve your code by using meaningful variable names.

It's also not really clear what you want to do with this input. Do you want the input box to be displayed on multiple tabs? Or the value of the textInput to be shown on multiple tabs?

If the former, there's not an obvious way to do that, in my mind, without violating the "multiple elements with the same ID" clause. The latter would be much easier (just use a renderText and send it to a verbatimOutput), but I don't think that's what you're asking.

So what you really want is multiple text inputs (with distinct IDs) that are synchronized. That you can do in separate observers on your server using something like this:

ui <- pageWithSidebar(
headerPanel("Hello !"),
sidebarPanel(
tabsetPanel(
tabPanel("a",
textInput(inputId = "text1", label = "text1", value = "")),
tabPanel("b",
textInput(inputId = "text2", label = "text2", value = ""))
)
),

mainPanel()
)

INITIAL_VAL <- "Initial text"

server <- function(input,output, session){
# Track the current value of the textInputs. Otherwise, we'll pick up that
# the text inputs are initially empty and will start setting the other to be
# empty too, rather than setting the initial value we wanted.
cur_val <- ""

observe({
# This observer depends on text1 and updates text2 with any changes
if (cur_val != input$text1){
# Then we assume text2 hasn't yet been updated
updateTextInput(session, "text2", NULL, input$text1)
cur_val <<- input$text1
}
})

observe({
# This observer depends on text2 and updates text1 with any changes
if (cur_val != input$text2){
# Then we assume text2 hasn't yet been updated
updateTextInput(session, "text1", NULL, input$text2)
cur_val <<- input$text2
}
})

# Define the initial state of the text boxes
updateTextInput(session, "text1", NULL, INITIAL_VAL)
updateTextInput(session, "text2", NULL, INITIAL_VAL)

}

runApp(list(ui=ui,server=server))

There's probably a cleaner way to set the initial state than the cur_val I'm tracking. But I couldn't think of something off the top of my head, so there it is.



Related Topics



Leave a reply



Submit