dynamic创build带有shiny图的标签,而无需重新创build现有标签
我想创builddynamic标签,每当用户点击一个button,一个新的标签将被创build。 每个选项卡具有相同的内容,用户可以使用各种小部件来select要绘制哪组数据。
目前,我在这里使用的解决scheme来dynamic创build我的标签,但随着lapply正在调用一个函数调用tabPanel,并添加内容到标签
`
renderUI({ some_data <- # Dataframe that data is extracted goes here createTabs <- function(tabNum, some_data) { tabPanel(title = paste("Map", tabNum, sep=" "), fluidRow( column( width = 3, wellPanel( #widgets are added here } mTabs <- lapply(0:input$map, createTabs, some_data) do.call(tabsetPanel, mTabs) })
`
这里的for循环的方法在这里发布,以在每个选项卡上创build图表。
但是,似乎不是创build一个新的选项卡,上述两个解决scheme都重新创build所有现有的选项卡。 所以如果当前有10个标签打开,所有10个标签都会被重新创build。 不幸的是,这也会重置每个选项卡上的所有用户设置(除了减慢应用程序的运行速度),还必须执行额外的规定,这会进一步减慢应用程序的速度,因为必须创build大量的input对象。
我看到一个菜单项的解决scheme似乎解决了这个问题,只需将所有的菜单项存储在一个列表中,每当生成一个新的菜单项时,它就被简单地添加到列表中,需要创build。 是这样的标签和渲染情节的可能吗?
这是代码:
newTabs <- renderMenu({ menu_list <- list( menu_vals$menu_list) sidebarMenu(.list = menu_list) }) menu_vals = reactiveValues(menu_list = NULL) observeEvent(eventExpr = input$placeholder, handlerExpr = { menu_vals$menu_list[[input$placeholder]] <- menuSubItem(paste("Saved Simulation", length(menu_vals$menu_list) + 1, sep = " "), tabName = paste("saved_sim", length(menu_vals$menu_list) + 1)) })
如果有人能向我解释menu_list < – list(menu_vals $ menu_list)在做什么,为什么Rstudio说它必须在一个被动expression式中,为什么用menu_list = null创build了一个名为menu_vals的新列表,这将不胜感激好 :)
编辑:我想我可以防止每一次创build一个新的标签重新创build的情节,也绕过了使用最大数量的情节
observeEvent(eventExpr = input$map, handlerExpr = { output[[paste0("outputComparePlot",simNum,"-",input$map)]] <- outputComparePlot(sessionEnv, config, react, input, simNum, input$map) #This function contains the call to renderPlot })
但是,我仍然无法弄清楚如何使用它来创build标签。 我尝试了相同的方法,但没有奏效。
我想提出一个解决scheme, 添加一个function ,应该已经实现shiny基地很久以前。 将tabPanels添加到现有的tabsetPanels的函数 。 我已经在这里和这里尝试了类似的东西,但这一次,我觉得这个解决scheme更加稳定和多function。
对于这个function,你需要插入4个代码到你的shiny的应用程序。 然后,您可以通过调用addTabToTabset
将任何一组具有任何内容的tabPanels
添加到现有的addTabToTabset
。 它的参数是一个tabPanel
(或一个tabPanels
列表 )和您的目标tabsetPanel
的名称(id)。 它甚至适用于navbarPage
,如果你只是想添加正常的tabPanels
。
应该被复制的代码在“重要! 注释。
我的意见可能不足以把握真正发生的事情(当然也是为什么)。 所以,如果你想更详细的,请留言,我会尽力详细说明。
复制 – 粘贴 – 运行 – 玩!
library(shiny) ui <- shinyUI(fluidPage( # Important! : JavaScript functionality to add the Tabs 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); }); "))), # End Important 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 )) 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)