I adapted the code from here.
This is my code:
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(shinydashboardPlus)
shinyApp(
ui = dashboardPage(
header = dashboardHeader(userOutput("user")),
sidebar = dashboardSidebar(),
body = dashboardBody(uiOutput("body")),
title = "DashboardPage"
),
server = function(input, output) {
output$user <- renderUser({
dashboardUser(
name = "Divad Nojnarg",
image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
title = "shinydashboardPlus",
subtitle = "Author",
footer = p("The footer", class = "text-center"),
fluidRow(
actionButton("btn1","Click")
)
)
})
observeEvent(input$btn1, { #Not triggering
output$body <- renderUI({print("Clicked")})
})
}
)
What I want is the user box (what is in red) not to remain active (I mean, to make it to disappear) when I click on the button.
Any suggestion?
One workaround to do this is to use shinyjs::hide() and shinyjs::show(). Targeting the action button inside the user is easy. The tricky part is to get the dashboard user to show up again when the dropdown menu is clicked. For this we can rewrite the dashboardUser() function and add an action link with id instead of the "normal" link. See comments in code:
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyjs)
dashboardUser
myDashboardUser <- function (..., name = NULL, image = NULL, title = NULL, subtitle = NULL,
footer = NULL)
{
if (!is.null(title)) {
line_1 <- paste0(name, " - ", title)
}
else {
line_1 <- name
}
if (!is.null(subtitle)) {
user_text <- shiny::tags$p(line_1, shiny::tags$small(subtitle))
user_header_height <- NULL
}
else {
user_text <- shiny::tags$p(line_1)
user_header_height <- shiny::tags$script(
shiny::HTML("$(\".user-header\").css(\"height\", \"145px\")")
)
}
userTag <- shiny::tagList(
shiny::tags$head(
shiny::tags$script("$(function() {\n
$('.dashboard-user').on('click', function(e){\n
e.stopPropagation();\n
});\n
});\n
")),
# we need to add an id and the class `action-button` to this link
shiny::tags$a(id = "user_dropdown",
href = "#",
class = "dropdown-toggle action-button",
`data-toggle` = "dropdown",
shiny::tags$img(src = image,
class = "user-image",
alt = "User Image"),
shiny::tags$span(class = "hidden-xs",
name)
),
shiny::tags$ul(class = "dropdown-menu dashboard-user",
shiny::tags$li(class = "user-header",
if (!is.null(user_header_height)) user_header_height,
shiny::tags$img(src = image,
class = "img-circle",
alt = "User Image"),
user_text),
if (length(list(...)) > 0)
shiny::tags$li(class = "user-body", ...),
if (!is.null(footer))
shiny::tags$li(class = "user-footer", footer)
)
)
userTag
}
}
shinyApp(
ui = dashboardPage(
header = dashboardHeader(userOutput("user")),
sidebar = dashboardSidebar(),
body = dashboardBody(
# make ShinyJs available
useShinyjs(),
uiOutput("body")
),
title = "DashboardPage"
),
server = function(input, output) {
output$user <- renderUser({
myDashboardUser(
name = "Divad Nojnarg",
image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
title = "shinydashboardPlus",
subtitle = "Author",
footer = p("The footer", class = "text-center"),
fluidRow(
actionButton("btn1","Click")
)
)
})
# use shinyjs::hide on button and also remove class open from user menue
observeEvent(input$btn1, {
hide(selector = ".dropdown-menu.dashboard-user")
removeClass(id = "user", class = "open")
})
# use shinyjs::show on new link
observeEvent(input$user_dropdown, {
show(selector = ".dropdown-menu.dashboard-user")
})
}
)
As I realized that by clicking anywhere, the user box disappear, I have just used a piece of javascript code to simulate clicking over "body" element:
jscode<-
'var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
var cb = document.getElementById("body");
var simulateClick = cb.dispatchEvent(evt);'
My final version:
library(shiny)
library(shinyWidgets)
library(shinydashboard)
library(shinydashboardPlus)
shinyApp(
ui = dashboardPage(
header = dashboardHeader(userOutput("user")),
sidebar = dashboardSidebar(),
body = dashboardBody(useShinyjs(), uiOutput("body")),
title = "DashboardPage"
),
server = function(input, output) {
output$user <- renderUser({
dashboardUser(
name = "Divad Nojnarg",
image = "https://adminlte.io/themes/AdminLTE/dist/img/user2-160x160.jpg",
title = "shinydashboardPlus",
subtitle = "Author",
footer = p("The footer", class = "text-center"),
fluidRow(
actionButton("btn1","Click")
)
)
})
observeEvent(input$btn1, { #Not triggering
output$body <- renderUI({print("Clicked")})
jscode<-
'var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
var cb = document.getElementById("body");
var simulateClick = cb.dispatchEvent(evt)';
runjs(jscode)
})
}
)
Related
I am trying to stylize my UI in a shiny app that I am making. I had previously built a fairly comprehensive map that I now have to modularize to improve readability by setting the map background as a transparent layer. Unfortunately, I cannot seem to understand how to go about applying CSS styles while using modules.
mapUI <- function(id) {
ns <- NS(id)
leafletOutput(ns("map"),width =250 , height = 250))
}
basin <- rgdal::readOGR("data/basin.kml", "basin")
ui <- pagePiling(
tags$head(
tags$link(rel = "stylesheet", type = "text/css", href = "style.css")),
sections.color = c('#f2f2f2', '#2C3E50', '#39C'),
opts = options,
menu = c("Start" = "start",
"Station 1" = "station1",
"Station 2" = "station2"
),
pageSectionImage(
center = TRUE,
img = "image1.jpg",
menu = "start",
mapUI("map1")
),
pageSectionImage(
center = TRUE,
img ="image2.jpg",
menu = "station1",
mapUI("map2")
),
pageSectionImage(
center = TRUE,
img ="image3.jpg",
menu = "station2",
mapUI("map3")
)
)
server <- function(input, output){
mapServer <- function(id) {
moduleServer(
id,
function(input, output, session) {
output$map<-renderLeaflet({
leaflet(options = leafletOptions(zoomControl = FALSE, minZoom = 5, maxZoom = 5))%>%
addPolygons(data = basin,color = "white",weight = 2,opacity = 1,fillOpacity = 0.9 )
})
})
}
mapServer("map1")
mapServer("map2")
}
here is the style.css that doesn't work for me!
#bottommap-map{
background: rgba(0,0,0,0.05);
}
I'm trying to scaffold together a basic dashboard using the shinymaterial package (https://ericrayanderson.github.io/shinymaterial/) but having a slight issue where my dropdown menus (usually selectInput in regular shiny apps) don't show up in a nested UI module.
There should be two dropdown menus above the "Settings" button in this screenshot:
Here's the code snippet for my scaffolding so far:
library(shiny)
library(shinymaterial)
# Wrap shinymaterial apps in material_page
ui <- material_page(
title = "App Title",
nav_bar_fixed = FALSE,
nav_bar_color = "black",
background_color = "white",
# font_color = "black",
# Place side-nav in the beginning of the UI
material_side_nav(
fixed = FALSE,
# Place side-nav tabs within side-nav
material_side_nav_tabs(
side_nav_tabs = c(
"Home" = "home",
"About" = "about"
),
icons = c("home", "help")
),
background_color = "white"
),
# Define side-nav tab content
material_side_nav_tab_content(
side_nav_tab_id = "home",
material_row(
material_column(
material_card(title = NULL,
sidebarCharts("main"),
depth = NULL),
width = 2,
offset = 0
),
material_column(
material_card(title = NULL,
"Chart goes here",
depth = NULL),
width = 10,
offset = 0
)
)
),
material_side_nav_tab_content(
side_nav_tab_id = "about",
tags$h1("About")
)
)
server <- function(input, output, session) {
callModule(chartSettings, "main")
}
# Server modules
chartSettings <- function(input, output, session) {
## 'Home' tab -- Sidebar
output$selectRootSymbol <- renderUI({
.choices <- c('a','b','c')
tagList(
helpText("Root Symbol:"), # Note: helpText() looks a little cleaner versus using the 'label' parameter in selectInput() below
# selectInput(session$ns("reactiveRootSymbol"), label = NULL, choices = .choices, selected = NULL, width = '100%')
material_dropdown(session$ns("reactiveRootSymbol"), label = NULL, choices = .choices, selected = NULL, width = '100%')
)
})
output$selectSymbol <- renderUI({
req(input$reactiveRootSymbol)
.choices <- c('d', 'e', 'f')
tagList(
helpText("Symbol:"),
# selectInput(session$ns("reactiveSymbol"), label = NULL, choices = toupper(.choices), selected = NULL, width = '100%')
material_dropdown(session$ns("reactiveSymbol"), label = NULL, choices = toupper(.choices), selected = NULL, width = '100%')
)
})
}
sidebarCharts <- function(id) {
ns <- NS(id)
tagList(
uiOutput(ns("selectRootSymbol")),
uiOutput(ns("selectSymbol")),
# actionButton(ns("settings"), "Settings", icon = icon("cogs"), width = '100%', class = "btn btn-primary"),p()
material_button(ns("settings"), "Settings", icon = "settings")
)
}
shinyApp(ui = ui, server = server)
I think I have a namespace issue, but I'm not sure (since the button does show up in the nested module). What am I doing wrong?
Any help is much appreciated!
There are at least two issues here.
1. material_dropdown does not display (resolved)
This appears to be due to the unused width = 100% option inside material_dropdown(). Removing this results in some of the drop downs displaying and all of the labels displaying.
2. Consecutive material_dropdown does not display (unresolved)
Having two consecutive material_dropdown's results in only the first drop down displaying, even though both labels display. There have been previous bugs with material_dropdown in the shinymaterial package so this could be part of a related issue.
Here is the code following my exploration:
library(shiny)
library(shinymaterial)
# submodule UI
sidebarCharts <- function(id) {
ns <- NS(id)
tagList(
uiOutput(ns("selectRootSymbol")),
uiOutput(ns("selectSymbol")),
# actionButton(ns("settings"), "Settings", icon = icon("cogs"), width = '100%', class = "btn btn-primary"),p()
material_button(ns("settings"), "Settings", icon = "settings")
)
}
# submodule server
chartSettings <- function(input, output, session) {
## 'Home' tab -- Sidebar
output$selectRootSymbol <- renderUI({
.choices <- c('a','b','c')
material_dropdown(session$ns("reactiveRootSymbol"), label = "Root Symbol:", choices = .choices)
})
output$selectSymbol <- renderUI({
# req(input$reactiveRootSymbol)
.choices <- c('d', 'e', 'f')
material_dropdown(session$ns("reactiveSymbol"), label = "Symbol:", choices = .choices)
})
}
## Wrap shinymaterial apps in material_page ----
ui <- material_page(
title = "App Title",
nav_bar_fixed = FALSE,
nav_bar_color = "black",
background_color = "white",
# font_color = "black",
# Place side-nav in the beginning of the UI
material_side_nav(
fixed = FALSE,
# Place side-nav tabs within side-nav
material_side_nav_tabs(
side_nav_tabs = c(
"Home" = "home"
),
icons = c("home")
),
background_color = "white"
),
# Define side-nav tab content
material_side_nav_tab_content(
side_nav_tab_id = "home",
material_row(
material_column(
material_card(title = NULL,
sidebarCharts("main"),
depth = NULL),
width = 2,
offset = 0
),
material_column(
material_card(title = NULL,
"Chart goes here",
depth = NULL),
width = 10,
offset = 0
)
)
)
)
## main server ----
server <- function(input, output, session) {
callModule(chartSettings, "main")
}
## run ----
shinyApp(ui = ui, server = server)
when input$variable change
uiOutput(1) and uiOutput(2) are rendered at the same time?
Is there any way render step by step not synchronistically?
The following is the steps I want.
1) input variable change
2) uiOutput(1) rendering
3) uiOutput(2) rendering
when input variable change shiny page is not working properly.
but after resizing the page window, the screen appears correctly.
Each time I change the input value, i have to recalibrate the page size.
ui.R
library(shiny)
library(shinydashboard)
sidebar <- dashboardSidebar(
radioButtons(inputId = "sidebar_data_sell",
label = "",
choices = c("Sell-in" = "sell_in", "Sell-out" = "sell_out"),
selected = "sell_out",
inline = TRUE),
uiOutput("summary_sidebar_ui")
)
ui <- dashboardPage(
dashboardHeader(title = h5("Hi")),
sidebar,
uiOutput("dashboard_body")
)
server.R
convertMenuItem <- function(mi, tabName) {
mi$children[[1]]$attribs['data-toggle'] = "tab"
mi$children[[1]]$attribs['data-value'] = tabName
mi
}
out_product_main <- function() {
list(
fluidPage(h5("product")))
}
product_items <- function() {
list(
selectInput("product_product_sell",
"product",
choices = list("product1" = "prd1", "product2" = "prd2"),
selected = c("prd1"))
)
}
in_overview_main <- function() {
list(
fluidPage(h5("overview")))
}
overview_items <- function() {
list(
radioButtons("overview_period_sell",
"period",
choices = c("year","month"),
inline = TRUE,
selected = "month")
)
}
shinyServer(function(input, output) {
output$summary_sidebar_ui <- renderUI({
if (input$sidebar_data_sell == "sell_in")
{
sidebarMenu(id = "summary_item",
convertMenuItem(menuItem("Overview",
tabName = "in_overview",
icon = icon("signal", lib = 'font-awesome'),
overview_items()),
tabName = 'in_overview'))
}
else{
sidebarMenu(id = "p_analysis_item",
convertMenuItem(menuItem("Product",
tabName = "out_product",
icon = icon("product-hunt", lib='font-awesome'),
product_items()),
tabName = 'out_product')
)
}
})
output$dashboard_body <- renderUI({
if (input$sidebar_data_sell == "sell_in") {
dashboardBody(tabItems(tabItem("in_overview", in_overview_main())))
}
else {
dashboardBody(tabItems(tabItem("out_product", out_product_main())))
}
})
})
When including a dropdown in a header with message or notification items it automatically displays the sentence "You have 1 messages" upon click. How can I only show the message but not the sentence "You have 1 messages"?
example to reproduce below:
ui <- dashboardPage(
dashboardHeader(dropdownMenu(type = "messages",
messageItem(
from = "Sales Dept",
message = "Sales are steady this month."
))),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) { }
shinyApp(ui, server)
It appears that sentence is hardcoded in the dropdownMenu function:
function (..., type = c("messages", "notifications", "tasks"),
badgeStatus = "primary", icon = NULL, .list = NULL)
{
type <- match.arg(type)
if (!is.null(badgeStatus)) validateStatus(badgeStatus)
items <- c(list(...), .list)
lapply(items, tagAssert, type = "li")
dropdownClass <- paste0("dropdown ", type, "-menu")
if (is.null(icon)) {
icon <- switch(type, messages = shiny::icon("envelope"),
notifications = shiny::icon("warning"), tasks = shiny::icon("tasks"))
}
numItems <- length(items)
if (is.null(badgeStatus)) {
badge <- NULL
}
else {
badge <- span(class = paste0("label label-", badgeStatus),
numItems)
}
tags$li(
class = dropdownClass,
a(
href = "#",
class = "dropdown-toggle",
`data-toggle` = "dropdown",
icon,
badge
),
tags$ul(
class = "dropdown-menu",
tags$li(
class = "header",
paste("You have", numItems, type)
),
tags$li(
tags$ul(class = "menu", items)
)
)
)
}
We see that the sentence is built with paste("You have", numItems, type).
One way to change that is to write a new function which take a new parameter with the sentence you want:
customSentence <- function(numItems, type) {
paste("This is a custom message")
}
# Function to call in place of dropdownMenu
dropdownMenuCustom <- function (..., type = c("messages", "notifications", "tasks"),
badgeStatus = "primary", icon = NULL, .list = NULL, customSentence = customSentence)
{
type <- match.arg(type)
if (!is.null(badgeStatus)) shinydashboard:::validateStatus(badgeStatus)
items <- c(list(...), .list)
lapply(items, shinydashboard:::tagAssert, type = "li")
dropdownClass <- paste0("dropdown ", type, "-menu")
if (is.null(icon)) {
icon <- switch(type, messages = shiny::icon("envelope"),
notifications = shiny::icon("warning"), tasks = shiny::icon("tasks"))
}
numItems <- length(items)
if (is.null(badgeStatus)) {
badge <- NULL
}
else {
badge <- span(class = paste0("label label-", badgeStatus),
numItems)
}
tags$li(
class = dropdownClass,
a(
href = "#",
class = "dropdown-toggle",
`data-toggle` = "dropdown",
icon,
badge
),
tags$ul(
class = "dropdown-menu",
tags$li(
class = "header",
customSentence(numItems, type)
),
tags$li(
tags$ul(class = "menu", items)
)
)
)
}
An a minimal example:
ui <- dashboardPage(
dashboardHeader(dropdownMenuCustom(type = "messages",
customSentence = customSentence,
messageItem(
from = "Sales Dept",
message = "Sales are steady this month."
))),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output) { }
shinyApp(ui, server)
This question might seem to be a duplicate, but let me explain why it's not.
I want to create a shiny navbarPage that has fixed elements and a reactive number of tabPanels, that reacts to other input elements. There are many questions about how to create reactive tabsetPanels/navbarPages but they mostly aim for what it has to look like. The most common answer (and the answer i don't seek) is to render the whole navbarPage with updated set of tabPanels. I am aware of that concept and I used it in the code below.
Here is what I want my app to look like:
library(shiny)
runApp(
shinyApp(
ui = shinyUI(
fluidPage(
uiOutput("navPage")
)
),
server = function(input, output, session){
MemoryValue1 <- 1
MemoryValue2 <- 1
makeReactiveBinding("MemoryValue1")
observeEvent(input$button, {
output[[paste0("plot_", input$number)]] <- renderPlot({
hist(rnorm(1000))
})
})
observeEvent(input$insidepanels, {
MemoryValue1 <<- input$insidepanels
})
observeEvent(input$number, {
MemoryValue2 <<- input$number
})
output$navPage <- renderUI({
OutsidePanel1 <- tabPanel("Outside1",
numericInput("insidepanels", label = "Number of panels inside NavMenu", value = isolate(MemoryValue1), step = 1, min = 1),
numericInput("number", label = "Panel to add Output-Element to", value = 1, step = isolate(MemoryValue2), min = 1),
actionButton("button", label = "Add Output-Element")
)
OutsidePanel2 <- tabPanel("Ouside2", "Outside 2")
InsidePanels <- lapply(1:MemoryValue1, function(x){tabPanel(paste0("Inside", x), plotOutput(paste0("plot_", x)))})
do.call(navbarPage, list("Nav", OutsidePanel1, OutsidePanel2, do.call(navbarMenu, c("Menu", InsidePanels))))
})
}
)
)
As you might have seen, it takes a lot of effort to store your input values if they are inside other panels and will be re-rendered = reset all the time. I find this solution to be illegible and slow, because of unnecessary rendering. It also interrupts the user who is clicking through values of input$insidepanels.
What I want the app to be like is that the Outside Panels are fixed and dont re-render. The main problem is that inside shiny, navbarPage on rendering distributes HTML elements to two different locations. Inside the navigation panel and to the body as tab content. That means a-posteori added elements will not be properly embedded.
So far, I have tried to create the navbarPage with custom tags and have dynamic output alter only parts of it. That works pretty well with the navigation panel, but not with tab contents. The reason is that all tabs (their div containers) are listed one after another and as soon as I want to inject multiple at once, I am offthrown by htmlOutput, since it (seemingly) has to have a container and cannot just deliver plain HTML. Thus, all custom tabs are not recongnized properly.
Here my code so far:
library(shiny)
runApp(
shinyApp(
ui = shinyUI(
fluidPage(
tags$nav(class = "navbar navbar-default navbar-static-top", role = "navigation",
tags$div(class = "container",
tags$div(class = "navbar-header",
tags$span(class = "navbar-brand", "Nav")
),
tags$ul(class = "nav navbar-nav",
tags$li(
tags$a(href = "#tab1", "data-toggle" = "tab", "data-value" = "Outside1", "Outside1")
),
tags$li(
tags$a(href = "#tab2", "data-toggle" = "tab", "data-value" = "Outside2", "Outside2")
),
tags$li(class = "dropdown",
tags$a(href = "#", class = "dropdown-toggle", "data-toggle" = "dropdown", "Menu1"),
htmlOutput("dropdownmenu", container = tags$ul, class = "dropdown-menu")
)
)
)
),
tags$div(class = "container-fluid",
tags$div(class = "tab-content", id = "tabContent",
tags$div(class = "tab-pane active", "data-value" = "Outside1", id = "tab1",
numericInput("insidepanels", label = "Number of panels inside NavMenu", value = 1, step = 1, min = 1),
numericInput("number", label = "Panel to add Output-Element to", value = 1, step = 1, min = 1),
actionButton("button", label = "Add Output-Element")
),
tags$div(class = "tab-pane", "data-value" = "Outside2", id = "tab2", "Content 2"),
htmlOutput("tabcontents")
)
)
)
),
server = function(input, output, session){
observeEvent(input$button, {
output[[paste0("plot_", input$number)]] <- renderPlot({
hist(rnorm(1000))
})
})
output$dropdownmenu <- renderUI({
lapply(1:input$insidepanels, function(x){tags$li(tags$a(href = paste0("#tab-menu-", x), "data-toggle" = "tab", "data-value" = paste0("Inside", x), paste("Inside", x)))})
})
output$tabcontents <- renderUI({
tagList(
lapply(1:input$insidepanels, function(x){div(class = "tab-pane", "data-value" = paste("Inside", x), id = paste0("tab-menu-", x), plotOutput(paste0("plot_", x)))})
)
})
}
)
)
Note: I also tried to create HTML with JavaScript-Chunks that is triggered from inside server. This works for simple tab content, but I want my tabPanels to still have shiny output elements. I don't see how I can fit that in with JavaScript. That is why I included the plotOutput content in my code.
Thanks to anybody who can help solve this issue!
Finally came up with an own answer. I hope this can be a useful reference to others who try to understand shiny reactiveness. The answer is JavaScript for custom elements (rebuilding standard shiny elements) and using Shiny.unbindAll() / Shiny.bindAll() to achieve the reactivity.
Code:
runApp(
shinyApp(
ui = shinyUI(
fluidPage(
tags$script('
Shiny.addCustomMessageHandler("createTab",
function(nr){
Shiny.unbindAll();
var dropdownContainer = document.getElementById("dropdown-menu");
var liNode = document.createElement("li");
liNode.setAttribute("id", "dropdown-element-" + nr);
var aNode = document.createElement("a");
aNode.setAttribute("href", "#tab-menu-" + nr);
aNode.setAttribute("data-toggle", "tab");
aNode.setAttribute("data-value", "Inside" + nr);
var textNode = document.createTextNode("Inside " + nr);
aNode.appendChild(textNode);
liNode.appendChild(aNode);
dropdownContainer.appendChild(liNode);
var tabContainer = document.getElementById("tabContent");
var tabNode = document.createElement("div");
tabNode.setAttribute("id", "tab-menu-" + nr);
tabNode.setAttribute("class", "tab-pane");
tabNode.setAttribute("data-value", "Inside" + nr);
var plotNode = document.createElement("div");
plotNode.setAttribute("id", "plot-" + nr);
plotNode.setAttribute("class", "shiny-plot-output");
plotNode.setAttribute("style", "width: 100% ; height: 400px");
tabNode.appendChild(document.createTextNode("Content Inside " + nr));
tabNode.appendChild(plotNode);
tabContainer.appendChild(tabNode);
Shiny.bindAll();
}
);
Shiny.addCustomMessageHandler("deleteTab",
function(nr){
var dropmenuElement = document.getElementById("dropdown-element-" + nr);
dropmenuElement.parentNode.removeChild(dropmenuElement);
var tabElement = document.getElementById("tab-menu-" + nr);
tabElement.parentNode.removeChild(tabElement);
}
);
'),
tags$nav(class = "navbar navbar-default navbar-static-top", role = "navigation",
tags$div(class = "container",
tags$div(class = "navbar-header",
tags$span(class = "navbar-brand", "Nav")
),
tags$ul(class = "nav navbar-nav",
tags$li(
tags$a(href = "#tab1", "data-toggle" = "tab", "data-value" = "Outside1", "Outside1")
),
tags$li(
tags$a(href = "#tab2", "data-toggle" = "tab", "data-value" = "Outside2", "Outside2")
),
tags$li(class = "dropdown",
tags$a(href = "#", class = "dropdown-toggle", "data-toggle" = "dropdown", "Menu1"),
tags$ul(id = "dropdown-menu", class = "dropdown-menu")
)
)
)
),
tags$div(class = "container-fluid",
tags$div(class = "tab-content", id = "tabContent",
tags$div(class = "tab-pane active", "data-value" = "Outside1", id = "tab1",
numericInput("insidepanels", label = "Number of panels inside NavMenu", value = 0, step = 1),
numericInput("number", label = "Panel to add Output-Element to", value = 0, step = 1),
actionButton("button", label = "Add Output-Element")
),
tags$div(class = "tab-pane", "data-value" = "Outside2", id = "tab2", "Content 2")
)
)
)
),
server = function(input, output, session){
allOpenTabs <- NULL
observeEvent(input$insidepanels, {
if(!is.na(input$insidepanels)){
localList <- 0:input$insidepanels
lapply(setdiff(localList, allOpenTabs), function(x){
session$sendCustomMessage(type = "createTab", message = x)
})
lapply(setdiff(allOpenTabs, localList), function(x){
session$sendCustomMessage(type = "deleteTab", message = x)
})
allOpenTabs <<- localList
}
})
observeEvent(input$button, {
output[[paste0("plot-", input$number)]] <- renderPlot({
hist(rnorm(1000))
})
})
}
), launch.browser = TRUE
)
It is basically adding the HTML Elements "by hand" and linking them to shiny listeners.