R Shiny : Dynamically creating tabs with output within navbarPage()

标签 r dynamic shiny navbar tabpanel

我正在尝试使用 navbarPage() (或类似的东西)创建一个应用程序,您可以在侧边栏中选择某些输入,当您单击按钮时,它将在单独的窗口中显示结果标签。我创建了一个示例,使用 script of K.Rohde下面(请注意,我在脚本中留下了他的原始评论)。

在此示例中,您在侧边栏中选择 4 个字母,如果单击该按钮,它会动态创建一个带有文本输出的单独选项卡。当我使用 fluidPage() 时,它工作得很好,但我想使用 navbarPage() 或类似的东西,因为我的最终脚本包含更多页面。

当我使用navbarPage()时,脚本不再工作:

  • 当您点击动态创建的选项卡时,该选项卡的输出将在空白页面而不是选项卡本身中打开。

我尝试通过在用户界面和服务器中使用 tabsetPanel()tabPanel 来修复它,但这不起作用。 SBista 认为 navbarPage() 似乎搞乱了 Javascript 功能,正如我的 previous post 中提到的那样.

如果有任何帮助,我将不胜感激!

用户界面:

ui <- navbarPage("Shiny",

  # 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

  tabPanel("Statistics"),

  tabPanel("Summary",
    sidebarLayout(
      sidebarPanel(width = 4,
                 selectInput(inputId = "choice_1", label = "First choice:",
                             choices = LETTERS, selected = "H", multiple = FALSE),
                 selectInput(inputId = "choice_2", label = "Second choice:",
                             choices = LETTERS, selected = "E", multiple = FALSE),
                 selectInput(inputId = "choice_3", label = "Third choice:",
                             choices = LETTERS, selected = "L", multiple = FALSE),
                 selectInput(inputId = "choice_4", label = "Fourth choice:",
                             choices = LETTERS, selected = "P", multiple = FALSE),
                 actionButton("goCreate", "Go create a new Tab!")
    ), 
    mainPanel(
      tabsetPanel(id = "mainTabset",
                  tabPanel("InitialPanel1", "Some text here to show this is InitialPanel1",
                           textOutput("creationInfo"),
                           # 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 

  output$creationInfo <- renderText({
    paste0("The next tab will be named: Results ", input$goCreate + 1)
  })

  observeEvent(input$goCreate, {
    nr <- input$goCreate

    newTabPanels <- list(
      tabPanel(paste0("NewTab ", nr),

               htmlOutput(paste0("Html_text", nr)),
               actionButton(paste0("Button", nr), "Some new button!"), 
               textOutput(paste0("Text", nr))
      )
    )

    output[[paste0("Html_text", nr)]] <- renderText({
        paste("<strong>", "Summary:", "</strong>", "<br>",
              "You chose the following letters:", isolate(input$choice_1), isolate(input$choice_2), isolate(input$choice_3), isolate(input$choice_4), "." ,"<br>",
              "Thank you for helping me!")
    })

    addTabToTabset(newTabPanels, "mainTabset")
  })
}

最佳答案

正如我在 answer 的评论中提到的javascript 功能似乎存在一些问题,在进一步引用 HTML 结构后,我发现 navbarPage 有两个 tab-contents。由于这个原因,javascript 失败了,所以稍微改变一下 javascript 功能实际上似乎可以工作。

你只需要改变
var tabContainerTarget = document.getElementsByClassName('tab-content')[0];

var tabContainerTarget = document.getElementsByClassName('tab-content')[1];

因此,如果您的 ui 使用新的 javascript 进行了如下更改,您的代码应该可以正常工作:

ui <- navbarPage("Shiny",

                 # 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')[1];

                                            /* 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

                 tabPanel("Statistics"),

                 tabPanel("Summary",
                          sidebarLayout(
                            sidebarPanel(width = 4,
                                         selectInput(inputId = "choice_1", label = "First choice:",
                                                     choices = LETTERS, selected = "H", multiple = FALSE),
                                         selectInput(inputId = "choice_2", label = "Second choice:",
                                                     choices = LETTERS, selected = "E", multiple = FALSE),
                                         selectInput(inputId = "choice_3", label = "Third choice:",
                                                     choices = LETTERS, selected = "L", multiple = FALSE),
                                         selectInput(inputId = "choice_4", label = "Fourth choice:",
                                                     choices = LETTERS, selected = "P", multiple = FALSE),
                                         actionButton("goCreate", "Go create a new Tab!")
                            ), 
                            mainPanel(
                              tabsetPanel(id = "mainTabset",
                                          tabPanel("InitialPanel1", "Some text here to show this is InitialPanel1",
                                                   textOutput("creationInfo"),
                                                   # Important! : 'Freshly baked' tabs first enter here.
                                                   uiOutput("creationPool", style = "display: none;")
                                                   # End Important
                                          )
                              )
                            )
                          )
                 )
                 )

关于R Shiny : Dynamically creating tabs with output within navbarPage(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46686288/

相关文章:

r - 年份顺序与组

R plotly : Custom hover text does not appear when only one stacked bar

php - 使用 PHP 从另一个数组动态构建多维数组?

excel - 防止 Excel 更改动态图表上的 x 轴

r - Shiny 中的 conditionalPanel 不起作用

r - 有没有办法在 Rmarkdown 中指定全局选项 block 函数,以便通过切换命令仅显示/不显示某些图形?

根据 R 中的值从矩阵返回列名称

ios - 以编程方式调用方法名称为 -(void)animatePageX 的方法的最佳实践,其中 x =1 到 25

r - 无法访问用于生成动态 Shiny 内容的函数内部的 react 对象

以 Shiny 的方式将 print(data.tree) 的输出渲染到 UI