2016-06-22 68 views
0

我爲Shiny應用程序使用HTML模板,並試圖根據URI的片段標識符複製儀表板的功能tabPanel

具體來說,給定一些充當頁面錨點的導航鏈接,我希望Shiny獲取該片段標識符,根據需要更新任何服務器端對象,並返回與用戶點擊的任何僞選項卡相對應的輸出上。這是基於Joe Cheng的college scorecard application(只是換出頁錨的查詢字符串)。我寧願不去查詢字符串的路由,因爲這個應用程序通過大量的用戶定義的選擇來源碼更大的數據集,這些選擇必須在URI中進行編碼。由於每次新的搜索都會觸發硬盤頁面刷新,因此每次對輸入進行較小更改時,這可能會導致數據重新加載,預處理等不太好的用戶體驗。

我遇到的問題是,有光澤僅存儲初始 URI在session$clientData散,有沒有辦法,我發現迫使它來更新(與invalidateLatereventReactive,或observeEvent)當用戶瀏覽從#summary#bleep#blorp。有沒有人遇到過類似的問題?或者是否可以刷新session$clientData對象而不刷新硬頁?

另一種選擇是向CSS添加一個新類,display: none;用於隱藏div,並寫一點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") 
    }) 
}) 

回答

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>