【问题标题】:shiny: start the app with hidden tabs, with NO delay闪亮:使用隐藏标签启动应用程序,没有延迟
【发布时间】:2018-06-14 06:18:03
【问题描述】:

我想构建一个应用程序,并且某些选项卡将对用户隐藏,直到他输入正确的密码。我知道如何使用shinyjs::hideTab:

library(shiny);library(shinyjs)
ui <- fluidPage(useShinyjs(),
  navbarPage("hello", id="hello",
             tabPanel("home", br(), h3("this is home"),passwordInput("pass", "enter 'password' to see the tabs: "),actionButton("enter", "enter")),
             tabPanel("tab2", br(), h4("this is tab2")),
             tabPanel("tab3 with a lot of stuff in it", br(), h4("this is tab3"))))
server <- function(input, output, session) {
  hideTab("hello", "tab2"); hideTab("hello", "tab3 with a lot of stuff in it")
  observeEvent(input$enter, {
    if (input$pass == "password"){showTab("hello", "tab2"); showTab("hello", "tab3 with a lot of stuff in it")}})}
shinyApp(ui, server)

不过有一点“东西”。在我的应用程序中,隐藏的选项卡有很多东西,如小部件、uiOutputs、绘图、图像、global.R 中的文件读取等。结果是加载时间更长,并且在应用程序的这段加载时间内(之前hideTab 指令运行)用户实际上看到了隐藏的选项卡,甚至可以单击它们并查看里面的内容。它们会保持“可见”状态大约 1 秒钟,然后隐藏起来。

有没有办法在 UI 构建之前立即隐藏它们?我更喜欢一个解决方案,而不必将我所有的 ui 代码都放入 server.R 脚本中......

谢谢

【问题讨论】:

  • 不幸的是,看起来没有一个很好的解决方案 (github.com/daattali/shinyjs/issues/43)。正如问题中提到的,一个想法可能是使用 CSS,但这可能比它的价值更多的努力
  • @MikeH。这里只是对程序的评论:在输入密码之前隐藏选项卡是非常不安全的。 style="display: none;" 可以简单地由用户通过在每个常用浏览器中单击右键来删除。在用户输入正确密码后,使用appendTab 创建选项卡可能会更好。

标签: javascript r shiny hide shinyjs


【解决方案1】:

您可以使用带有extendShinyjs() 的javascript 来隐藏页面加载时所需的标签:

Javascript 代码:

shinyjs.init = function(){
  $('#hello li a[data-value="tab3_val"]').hide();
  $('#hello li a[data-value="tab2_val"]').hide();
}

R 代码:

ui <- fluidPage(useShinyjs(),
                #Added this js
                extendShinyjs(script = path_to_javascript_file),
                navbarPage("hello", id="hello",
                           tabPanel("home", br(), h3("this is home"),passwordInput("pass", "enter 'password' to see the tabs: "),actionButton("enter", "enter")),
                           tabPanel("tab2", value = "tab2_val", br(), h4("this is tab2")),
                           tabPanel("tab3 with a lot of stuff in it", value = "tab3_val", br(), h4("this is tab3"))))

server <- function(input, output, session) {

  observeEvent(input$enter, {
    if (input$pass == "password"){
      show(selector = '#hello li a[data-value="tab3_val"]')
      show(selector = '#hello li a[data-value="tab2_val"]')
      }})}
shinyApp(ui, server)

另外,CSS 实际上并不太复杂。如果你想走这条路,你可以简单地将上面的 extendShinyjs() 调用替换为:

tags$head(tags$style(HTML("#hello li a[data-value = 'tab2_val'], #hello li a[data-value = 'tab3_val'] {
                             display: none;
 }")))

这样做的缺点是选项卡的格式在取消隐藏后似乎已关闭。

【讨论】:

  • 嗨@Mike H。感谢您的出色回答。这种奇怪的事情就像在密码输入后重新出现的选项卡名称具有顶部垂直对齐...与原始选项卡不同...如何纠正这个问题?
  • @agenis,它必须对display: none; 属性执行此操作。我将使用更好(简单)的 javascript 函数更新我的答案
  • 嗯,对我不起作用。它立即将其隐藏,但显示功能似乎不起作用。三重检查一切
  • @Danny 很难在没有看到代码的情况下说出问题所在。我唯一的猜测是检查选择器,但我假设你已经检查过了
  • 当使用tags$时,代码应该是tags$head(tags$script(而不是tags$head(tags$style(。
【解决方案2】:

我会选择renderUI(请参阅@BertilBaron 的回答)或appendTab,因为在隐藏选项卡时很容易绕过密码:

这里是如何通过appendTab 实现所需的行为,避免上面的基本闪亮,没有额外的 JS:

library(shiny)

ui <- fluidPage(navbarPage("hello", id = "hello",
  tabPanel(
    "home",
    br(),
    h3("this is home"),
    passwordInput("pass", "enter 'password' to see the tabs: "),
    actionButton("enter", "enter")
  )
))

server <- function(input, output, session) {
  observeEvent(input$enter, {
    if (input$pass == "password") {
      appendTab(inputId = "hello", tab = tabPanel("tab2", value = "tab2_val", br(), h4("this is tab2")))
      appendTab(inputId = "hello", tab = tabPanel("tab3 with a lot of stuff in it",value = "tab3_val", br(), h4("this is tab3")))
    }
  })
}

shinyApp(ui, server)

【讨论】:

  • 感谢您的出色回答。我明白了,使用这种方法而不是接受的答案将是隐藏的安全性/便利性之间的选择
  • 对于未来的读者:Here 是如何使用 sidebarPanel 而不是 navbarPage。
【解决方案3】:

这个怎么样

library(shiny);library(shinyjs)
ui <- fluidPage(useShinyjs(),
                navbarPage("hello", id="hello",
                           tabPanel("home", br(), h3("this is home"),passwordInput("pass", "enter 'password' to see the tabs: "),actionButton("enter", "enter")),
                           tabPanel("tab2",uiOutput("tab2Content")),
                           tabPanel("tab3 with a lot of stuff in it", uiOutput("tab3Content"))))
server <- function(input, output, session) {
  output$tab2Content <- renderUI({
    req(input$pass == "password")
    tagList(
      br(), 
      h4("this is tab2")
    )
  })
  output$tab3Content <- renderUI({
    req(input$pass == "password")
    tagList(
      br(), 
      h4("this is tab3")
    )
  })}
shinyApp(ui, server)

希望这会有所帮助!

【讨论】:

  • 谢谢,确实有效。然而,将所有选项卡传递到服务器脚本有点破坏应用程序的结构和可理解性,这就是我在问题中最后一句话的原因。
【解决方案4】:

我解决了这个问题,创建了一个新函数(在 UI 定义之上)以在右侧 li 标签中包含 style="display:none;:

tabsethidepanels<-function(tag, indexes = NULL) {
  if (class(tag) == "shiny.tag" && tag$name == "div" && tag$attribs$class == "tabbable") {
    if (is.null(indexes)) indexes<-seq_along(tag$children[[1]]$children[[1]])
    for (i in indexes) tag$children[[1]]$children[[1]][[i]]$attribs<-c(tag$children[[1]]$children[[1]][[i]]$attribs, list(style="display:none;"))
    tag
  } else stop("tag must be a tabsetPanel!", call. = F)
}

并相应地定义标签集:

tabsethidepanels(
  tabsetPanel(
    id = "mytab",
    selected = "tab7-not2hide",
    tabPanel("tab1"),
    tabPanel("tab2"),
    tabPanel("tab3"),
    tabPanel("tab4"),
    tabPanel("tab5"),
    tabPanel("tab6"),
    tabPanel("tab7-not2hide")
  ),
  indexes = 1:6
)

“索引”字段对于仅选择要隐藏的正确选项卡很有用:

<div class="tabbable">
  <ul class="nav nav-tabs shiny-tab-input" id="mytab" data-tabsetid="2818">
    <li style="display:none;">
      <a href="#tab-2818-1" data-toggle="tab" data-value="tab1">tab1</a>
    </li>
    <li style="display:none;">
      <a href="#tab-2818-2" data-toggle="tab" data-value="tab2">tab2</a>
    </li>
    <li style="display:none;">
      <a href="#tab-2818-3" data-toggle="tab" data-value="tab3">tab3</a>
    </li>
    <li style="display:none;">
      <a href="#tab-2818-4" data-toggle="tab" data-value="tab4">tab4</a>
    </li>
    <li style="display:none;">
      <a href="#tab-2818-5" data-toggle="tab" data-value="tab5">tab5</a>
    </li>
    <li style="display:none;">
      <a href="#tab-2818-6" data-toggle="tab" data-value="tab6">tab6</a>
    </li>
    <li class="active">
      <a href="#tab-2818-7" data-toggle="tab" data-value="tab7-not2hide">tab7-not2hide</a>
    </li>
  </ul>
  <div class="tab-content" data-tabsetid="2818">
    <div class="tab-pane" data-value="tab1" id="tab-2818-1"></div>
    <div class="tab-pane" data-value="tab2" id="tab-2818-2"></div>
    <div class="tab-pane" data-value="tab3" id="tab-2818-3"></div>
    <div class="tab-pane" data-value="tab4" id="tab-2818-4"></div>
    <div class="tab-pane" data-value="tab5" id="tab-2818-5"></div>
    <div class="tab-pane" data-value="tab6" id="tab-2818-6"></div>
    <div class="tab-pane active" data-value="tab7-not2hide" id="tab-2818-7"></div>
  </div>
</div>

记得选择一个标签,不要隐藏为活动的selected = "tab7-not2hide"。

如果您需要隐藏我建议创建“空白”tabPanel 的所有选项卡,请将其选择为活动的并隐藏所有索引 = NULL 的选项卡。

【讨论】:

  • 请在问题下查看我的评论。使用appendTab 可能会更好。
  • @ismirsehregal 你是对的。当我不希望用户查看标签时,我只将此代码用于“化妆品/造型”问题。如果程序员有“安全”原因,我同意 appendTab 或 uiOutput/renderUI 是更好的答案。谢谢。
猜你喜欢
  • 2017-02-21
  • 1970-01-01
  • 2017-12-25
  • 1970-01-01
  • 2019-02-21
  • 2021-12-01
  • 1970-01-01
  • 2015-09-08
  • 2021-05-18
相关资源
最近更新 更多