转到下一个和上一个选项卡的通用按钮 [英] Generic button for go to next and previous tabItem Shiny

查看:145
本文介绍了转到下一个和上一个选项卡的通用按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这与以前提出的问题非常接近,但是在对这些示例进行深入研究之后,我还没有找到针对我的特定问题的解决方案.

I know this is pretty close to previously aked questions, but after thorough study of those examples I haven't found a solution for my particular problemm yet.

我有一个使用此结构(* 1)的Shiny Dashboard的闪亮应用程序.我可以这样制作下一页或上一页按钮:

I have a shiny App using Shiny Dashboard with this structure (*1). I can make a next or previous page button this way:

next_btn        <-    actionButton(   inputId ="Next1", 
                                      label = icon("arrow-right"))

有观察者:

  observeEvent(input$Next1, {
    updateTabItems(session, "tabs", "NAME")
  })               

其中NAME是tabItem ID.这个版本比我发现的使用switch和/或

where NAME is the tabItem ID. This version is simpler than the expamples I've found that use switch and or simply Navigate to particular sidebar menu item in ShinyDashboard?

但是,这仅适用于使用特定按钮从pagename1切换到pagename2的情况.

However, this only works to switch from pagename1 to pagename2 with a specific button for it.

但是我的应用程序中有10-20个tabItem:**<--问题的原因**

I have however, 10-20 tabItems in my app : ** <<- the reason for my problem**

提到的方法要求我为每个页面编写一个actionbutton(next1,... ac但下2个,下3个等.每个页面分别为1个,并且每个页面都有一个单独的观察者.

The approach mentioned about would require me to write a actionbutton(next1, ... ac but next 2 , next 3 etc. 1 for each page, and also an separate observer for each.

我想做的是这样的:

1个通用操作按钮,称为"NEXTPAGE" 与执行updateTabItems(会话,标签,当前页面+1"的

1 generic action button called "NEXTPAGE" with an observer that does updateTabItems(session, tabs, "current page +1"

以丢失的任何方式转到当前页面+1.我可以想象创建一个包含所有选项卡名称的列表参数,在该列表中找到当前选项卡名称,抓住它的位置,例如向上(上一个)或向下(下一个)上移一个位置. 但是,除了一些非常费力的手动键入字符串列表之外,我不知道如何获取应用程序中存在的所有tabItem的列表变量.

to to the current page +1 in whatever way I'm lost. I could imagine making a list parameter of all tab names, find the current tabname in that list, grab it's position, shift one position up (previous), or down (next) for example. However, I do not know how to get a list variable of all tabItems present in my app, other than some very laborious manual typing of a list of strings.

* 1应用程序结构:

*1 app structure:

library(shiny)
library(shinydashboard)

### create general button here like: 
### write a function that looks at what (nth) tabItem we are, and creates a ###  uiOutput for a next_n button (I can do this myself I think) 

dashboardHeader(title = "FLOW C.A.R.S."),
  dashboardSidebar(
    sidebarMenu(id = "tabs",
                menuItem("Home", tabName = "Home", icon = icon("home")),
                menuItem("My Page", tabName = "MyPage", icon =icon("download")),
                menuItem("Do math", tabName = "Math", icon=icon("folder-open")),
                menuItem("Results of something", tabName="Results", icon= 
 icon("file-text-o")),
              menuItem("Short Manual", tabName = "Manual", icon = icon("book"))
                )
    ),

  dashboardBody(
   tabItems(
    tabItem(tabName = "Home",  class = 'rightAlign',
    actionButton(   inputId ="Next1", label = icon("arrow-right"))),

    tabItem(tabName = "MyPage",  class = 'rightAlign',
    actionButton(   inputId ="Next2", label = icon("arrow-right")),
    actionButton(   inputId ="Previous2", label =  icon("arrow-left"))), 

    tabItem(tabName = "Math",  class = 'rightAlign',
    actionButton(   inputId ="Next3", label = icon("arrow-right")),
    actionButton(   inputId ="Previous3", label =  icon("arrow-left"))), 

    tabItem(tabName = "tabName",  class = 'rightAlign',
    actionButton(   inputId ="Next4", label = icon("arrow-right")),
    actionButton(   inputId ="Previous4", label =  icon("arrow-left"))), 

    tabItem(tabName = "Maual",  class = 'rightAlign',
    actionButton(   inputId ="Previous5", label =  icon("arrow-left")))
    ))


server: 

shinyServer = function(input, output, session) {


  observeEvent(input$Next1, {
    updateTabItems(session, "tabs", "MyPage)
  })

observeEvent(input$Previous2, {
    updateTabItems(session, "tabs", "Home")
  })

observeEvent(input$Next2, {
    updateTabItems(session, "tabs", "Math)
  })

 ### repeat for next2 and previous 2 , 3 etc 

}

总而言之,我正在寻找一个代码,该代码将为我们提供在当前选项卡之后的选项卡名称,以便我们可以将该查询的结果填充到updateTabItems(session,"tabs" ... ....)

Summary, I'm looking for a code that will give us the name of the Tab coming after of before the current tab, so that we can stuff the outcome of that query into updateTabItems(session, "tabs" .......)

这样我们就可以使观察者更具说服力.

so that we can make a more general observer that says for instance;

如果单击下一步[i]"按钮,请转到tabItem [i + 1]

if Next[i] button is clicked go to tabItem[i+1]

但是就像我说的,我只有在知道如何使用函数访问tabItems列表的情况下,才能想象自己编写了这样的代码(显然,因为我将所有标签都标记了,所以我在ui页面中拥有这些名称,但是我试图通过为每个页面/按钮/观察者输入全部代码来避免所有多余的代码重复)

but like I said, I can imagine myself writing such a code, if only if I knew how to access the list of tabItems with function (obviously I have the names in the ui page since I labelled all of them, but I'm trying to avoid all the redunant repetition of code by typing it all out for each page/button/observer)

到目前为止,我唯一发现的是观察者内部的paste(input $ tabs)将为您提供当前的标签,但是接下来呢...

only thing I discoverd so far is that paste(input$tabs) inside an observer will give you the current tab, but then what...

感谢安妮的帮助!

如果不清楚,请随时与我联系

If it's unclear, please feel free to contact me

推荐答案

我在评论中写道: 最简单的方法是确保重写代码并具有一个数组:tabItemNames = c("Home", "MyPage",....),然后相应地将选项卡命名为tabItem(tabName = tabItemNames[1],...)tabItem(tabName = tabItemNames[2],...等.那我就不会调用多余的代码了,...(另请参阅本杰明的答案.

As i wrote in the comment: The easiest would be for sure to rewrite the code and have an array: tabItemNames = c("Home", "MyPage",....) and then name the tabs accordingly tabItem(tabName = tabItemNames[1],...), tabItem(tabName = tabItemNames[2],... etc. That i wouldnt call redundant repition of code,...(see also Benjamin´s answer.

但是,我感谢JS挑战并试了一下: 您可以使用JS读取tabItemNames.这样可以满足不必在代码中进行硬编码的额外要求.

However, I appreciated the JS challenge and gave it a shot: You could use JS to read the tabItemNames. That would fulfill the bonus requirement of not having to hardcode them in the code.

  observe({
    runjs("
      function getAllElementsWithAttribute(attribute){
         var matchingElements = [];
         var allElements = document.getElementsByTagName('*');
         for (var i = 0, n = allElements.length; i < n; i++){
            if (allElements[i].getAttribute(attribute) !== null){
               matchingElements.push(allElements[i]);
            }
         }
         return matchingElements;
      };

      ahref = getAllElementsWithAttribute('data-toggle');
      var tabNames = [];
      var tabName = '';
      for (var nr = 0, n = ahref.length; nr < n; nr++){
         tabName = ahref[nr].hash.split('-')[2]
         if(tabName != 'Toggle navigation') tabNames.push(tabName)
      }
      Shiny.onInputChange('tabNames', tabNames);
      ")
  })

我假设您没有任何其他具有'data-toggle'属性的元素.如果无法实现,则必须在代码中集成更多条件.

The assumption i make that you do not have any further element having a 'data-toggle' attribute. If this would not be fulfilled one would have to integrate further conditions in the code.

在下面的一个运行示例中,将上面的代码与Benjamin提供的代码结合起来进行构建:

In the following a running example, build by the code above combined with the code provided by Benjamin:

library(shiny)
library(shinydashboard)
library(shinyjs)

app <- shinyApp(
  ui = 
    dashboardPage(
      dashboardHeader(title = "FLOW C.A.R.S."),
      dashboardSidebar(
        useShinyjs(),
        sidebarMenu(id = "tabs",
                    menuItem("Home", tabName = "Home", icon = icon("home")),
                    menuItem("My Page", tabName = "MyPage", icon =icon("download")),
                    menuItem("Do math", tabName = "Math", icon=icon("folder-open")),
                    menuItem("Results of something", tabName="Results", icon= 
                               icon("file-text-o")),
                    menuItem("Short Manual", tabName = "Manual", icon = icon("book"))
        )
      ),

      dashboardBody(
        actionButton(inputId ="Previous", label = icon("arrow-left")),
        actionButton(inputId ="Next", label = icon("arrow-right"))
      )
    ),

  server = 
    shinyServer(function(input, output, session){
      global <- reactiveValues(tab_id = "")
      tab_id <- c("Home", "MyPage", "Math", "Results", "Manual")

      Current <- reactiveValues(
        Tab = "Home"
      )

      observeEvent(
        input[["tabs"]],
        {
          Current$Tab <- input[["tabs"]]
        }
      )

      observeEvent(
        input[["Previous"]],
        {
          tab_id_position <- match(Current$Tab, input$tabNames) - 1
          if (tab_id_position == 0) tab_id_position <- length(input$tabNames)
          Current$Tab <- input$tabNames[tab_id_position]
          updateTabItems(session, "tabs", input$tabNames[tab_id_position]) 
        }
      )

      observeEvent(
        input[["Next"]],
        {
          tab_id_position <- match(Current$Tab, input$tabNames) + 1
          if (tab_id_position > length(input$tabNames)) tab_id_position <- 1
          Current$Tab <- input$tabNames[tab_id_position]
          updateTabItems(session, "tabs", input$tabNames[tab_id_position]) 
        }
      )

      observe({
        runjs("
          function getAllElementsWithAttribute(attribute){
             var matchingElements = [];
             var allElements = document.getElementsByTagName('*');
             for (var i = 0, n = allElements.length; i < n; i++){
                if (allElements[i].getAttribute(attribute) !== null){
                   matchingElements.push(allElements[i]);
                }
             }
             return matchingElements;
          };

          ahref = getAllElementsWithAttribute('data-toggle');
          var tabNames = [];
          var tabName = '';
          for (var nr = 0, n = ahref.length; nr < n; nr++){
             tabName = ahref[nr].hash.split('-')[2]
             if(tabName != 'Toggle navigation') tabNames.push(tabName)
          }
          Shiny.onInputChange('tabNames', tabNames);
          ")
      })


    })
)

runApp(app, launch.browser = TRUE)

从此处读取我使用的元素的javascript函数:

The javascript function to read the elements I used from here: Get elements by attribute when querySelectorAll is not available without using libraries?

这篇关于转到下一个和上一个选项卡的通用按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆