在闪亮的仪表板中动态创建选项卡

时间:2017-04-27 14:44:10

标签: r dynamic shiny shinydashboard tabpanel

由于K. Rohde解决方案(Dynamically creating tabs with plots in shiny without re-creating existing tabs),我成功制作了动态tabPanel。

但是,当我尝试在shinydashboard布局中导入它时,我观察到动态创建的tabPanel的奇怪行为:当我选择一个时,页面变为空,除了我在新面板中指定的内容。

我不明白为什么......似乎新的标签不会继承属于他人的布局元素(如果不使用shinydashboard,那么它应该是......也许?),并隐藏它们(!?)。当我点击另一个tabItem并返回时,在点击"动态标签"之前,所有内容都会显示。

这并不容易解释,所以这里有一个可重复的例子,它只是K. Rhode示例在shinydashboard布局中的转换:



library(shiny)
library(shinydashboard)

ui <- dashboardPage(skin = "green",
	dashboardHeader(title = 'Dynamic Tabs'),
	dashboardSidebar(
		sidebarMenu(id = "sidebarmenu",
			menuItem("Page1", tabName = "Page1",  icon = icon("map"), selected = TRUE),
			# just to show that coming back to page 1 from page 2 recall the good layout :
			menuItem("Page2", tabName = "Page2",  icon = icon("dashboard"), selected = FALSE) 
		)
	),
	dashboardBody(
		tags$head(tags$script(HTML("
			/* In coherence with the original Shiny way, tab names are created with random numbers. 
			To avoid duplicate IDs, we collect all generated IDs.  */
			var hrefCollection = [];
			
			Shiny.addCustomMessageHandler('addTabToTabset', function(message){
			var hrefCodes = [];
			/* Getting the right tabsetPanel */
			var tabsetTarget = document.getElementById(message.tabsetName);
			
			/* Iterating through all Panel elements */
			for(var i = 0; i < message.titles.length; i++){
			/* Creating 6-digit tab ID and check, whether it was already assigned. */
			do {
			hrefCodes[i] = Math.floor(Math.random()*100000);
			} 
			while(hrefCollection.indexOf(hrefCodes[i]) != -1);
			hrefCollection = hrefCollection.concat(hrefCodes[i]);
			
			/* Creating node in the navigation bar */
			var navNode = document.createElement('li');
			var linkNode = document.createElement('a');
			
			linkNode.appendChild(document.createTextNode(message.titles[i]));
			linkNode.setAttribute('data-toggle', 'tab');
			linkNode.setAttribute('data-value', message.titles[i]);
			linkNode.setAttribute('href', '#tab-' + hrefCodes[i]);
			
			navNode.appendChild(linkNode);
			tabsetTarget.appendChild(navNode);
			};
			
			/* Move the tabs content to where they are normally stored. Using timeout, because
			it can take some 20-50 millis until the elements are created. */ 
			setTimeout(function(){
			var creationPool = document.getElementById('creationPool').childNodes;
			var tabContainerTarget = document.getElementsByClassName('tab-content')[0];
			
			/* Again iterate through all Panels. */
			for(var i = 0; i < creationPool.length; i++){
			var tabContent = creationPool[i];
			tabContent.setAttribute('id', 'tab-' + hrefCodes[i]);
			
			tabContainerTarget.appendChild(tabContent);
			};
			}, 100);
			});
			"))),
		tabItems(
			tabItem(tabName = "Page1",
				tabsetPanel(id = "mainTabset", 
					tabPanel("InitialPanel1", "Some Text here to show this is InitialPanel1", 
						actionButton("goCreate", "Go create a new Tab!"),
						textOutput("creationInfo")
					),
					tabPanel("InitialPanel2", "Some Text here to show this is InitialPanel2 and not some other Panel")
				)
			),
			# Important! : 'Freshly baked' tabs first enter here.
			uiOutput("creationPool", style = "display: none;")
			# End Important
			,
			tabItem(tabName = "Page2", "Go back to page 1...")
		)
	)
)

server <- function(input, output, session){
	
	# Important! : creationPool should be hidden to avoid elements flashing before they are moved.
	#              But hidden elements are ignored by shiny, unless this option below is set.
	output$creationPool <- renderUI({})
	outputOptions(output, "creationPool", suspendWhenHidden = FALSE)
	# End Important
	
	# Important! : This is the make-easy wrapper for adding new tabPanels.
	addTabToTabset <- function(Panels, tabsetName){
		titles <- lapply(Panels, function(Panel){return(Panel$attribs$title)})
		Panels <- lapply(Panels, function(Panel){Panel$attribs$title <- NULL; return(Panel)})
		
		output$creationPool <- renderUI({Panels})
		session$sendCustomMessage(type = "addTabToTabset", message = list(titles = titles, tabsetName = tabsetName))
	}
	# End Important 
	
	# From here: Just for demonstration
	output$creationInfo <- renderText({
		paste0("The next tab will be named NewTab", input$goCreate + 1)
	})
	
	observeEvent(input$goCreate, {
		nr <- input$goCreate
		
		newTabPanels <- list(
			tabPanel(paste0("NewTab", nr), 
				actionButton(paste0("Button", nr), "Some new button!"), 
				textOutput(paste0("Text", nr))
			), 
			tabPanel(paste0("AlsoNewTab", nr), sliderInput(paste0("Slider", nr), label = NULL, min = 0, max = 1, value = 1))
		)
		
		output[[paste0("Text", nr)]] <- renderText({
			if(input[[paste0("Button", nr)]] == 0){
				"Try pushing this button!"
			} else {
				paste("Button number", nr , "works!")
			}
		})
		
		addTabToTabset(newTabPanels, "mainTabset")
			})
}

shinyApp(ui, server)
&#13;
&#13;
&#13;

干杯。

0 个答案:

没有答案