在会话$ clientData中更新Shiny中的片段标识符

时间:2016-06-22 13:42:11

标签: r shiny

我正在为一个Shiny应用程序使用HTML模板,并且我正在尝试复制仪表板' tabPanel基于URI的片段标识符的功能。

具体来说,鉴于许多导航链接充当页面锚点,我希望Shiny获取该片段标识符,根据需要更新任何服务器端对象,并返回与用户单击的任何伪标签对应的输出。这是基于Joe Cheng的college scorecard application(只需换出页面锚点的查询字符串)。我还不愿意使用查询字符串来访问该路由,因为该应用程序使用大量用户定义的选择来源更大的数据集,这些选择必须在URI中进行编码。由于每次新搜索都会触发硬页面刷新,因此每当您对输入进行微小更改时,这可能会导致数据重新加载,预处理等用户体验不佳。

我遇到的问题是,Shiny只会在session$clientData中存储初始 URI哈希值,并且我发现没有任何方法可以强制使用要在用户从invalidateLater导航到eventReactiveobserveEvent时更新(使用#summary#bleep#blorp)。有没有人遇到过类似的问题?或者是否可以在没有硬页面刷新的情况下刷新session$clientData对象?

另一种选择是只用display: none;为隐藏的div添加一个新类到CSS,并编写一些JS来处理事情。但理想情况下,我更愿意找到一种基于Shiny的解决方案。

我的代码类似于:

的index.html:

...
<header role="banner">
  <h3 class="usa-display">My header!</h3>
  <ul>
    <li><a class="nav active" href="#summary">Summary</a></li>
    <li><a class="nav" href="#blorp">Another Tab</a></li>
  </ul>
</header>

<div data-display-if="output.appMode === 'summary' ">
  {{ renderVerbatimText("clientInfo") }}
</div>

<div data-display-if="output.appMode === 'blorp' ">
  <img src="assets/img/failWhale.jpg" />
</div>
...

ui.R:

function(req) {
  htmlTemplate(
    "www/index.html"
  )
}

server.R:

parseHashString <- function (str, nested = FALSE) {
  if (is.null(str) || nchar(str) == 0) {
    values <- "summary"
    return(values)
  }

  if (substr(str, 1, 1) == "#") {
    str <- substr(str, 2, nchar(str))
  }

  values <- strsplit(str, "#", fixed = TRUE)[[1]]
  values <- values[!is.na(values)]

  values <- values[values %in% c("summary", "blorp")]

  return(values[1])
}

shinyServer(function(input, output, session) {
  output$appMode <- reactive({
    parseHashString(session$clientData$url_hash_initial)
  })

  outputOptions(output, "appMode", suspendWhenHidden = FALSE)


  output$clientInfo<- renderText({
    cdata <- session$clientData
    cnames <- names(cdata)

    allvalues <- lapply(cnames, function(name) {
      paste(name, cdata[[name]], sep=" = ")
    })
    paste(allvalues, collapse = "\n")
  })
})

1 个答案:

答案 0 :(得分:0)

我最终通过创建自定义Shiny输入来解决这个问题。基本上我只是创建了一个空/隐藏div来反映新的Shiny输入。最重要的是每个Rstudio's instructions只是一个非常标准的输入绑定。我必须做的唯一修改是在URI哈希改变时触发回调(在这种情况下,在用户点击任何导航链接之后)。导航点击会触发on("hashchange" function() {...}),然后强制input$appHash进行更新。无论新的URI哈希是什么,我都会在server.R中遵守任何逻辑,并且可以有条件地显示输出。

<强>的index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    {{ headContent() }}
    {{ bootstrapLib() }}

    <script>
      $(document).ready(function(){
        var hashBinding = new Shiny.InputBinding();
        $.extend(hashBinding, {
          find: function(scope) {
            return $(scope).find(".appHash");
          },
          getValue: function(el) {
            return $(el).val();
          },
          setValue: function(el, value) {
            $(el).val(value);
          },
          subscribe: function(el, callback) {
            $(el).on("change.hashBinding", function(e) {
              $(el).val(window.location.hash);
              callback();
            });
          },
          unsubscribe: function(el) {
            $(el).off(".hashBinding");
          }
        });

        Shiny.inputBindings.register(hashBinding);

        $('.nav').click(function () {
          $('.nav').removeClass('active');
          $(this).addClass('active');
        });

        $(window).on('hashchange', function() {
          var el = $(".appHash");
          el.trigger("change");
        });
      });
    </script>
  </head>

  <body>
    <header role="banner">
      <div class="appHash" id="appHash" style="display:none;"></div>
      <ul>
        <li><a class="nav active" href="#summary">Summary</a></li>
        <li><a class="nav" href="#bleep">Tab X</a></li>
        <li><a class="nav" href="#blorp">Tab Y</a></li>
        <li><a class="nav" href="#faq">F.A.Q.</a></li>
      </ul>
    </header>
  </body>
</html>