2016-06-22 12 views
0

私はShinyアプリケーション用のHTMLテンプレートを使用しており、URIのフラグメント識別子に基づいてダッシュボードのtabPanel機能を複製しようとしています。

具体的には、ページアンカーとして機能する多数のナビゲーションリンクがある場合、Shinyはそのフラグメント識別子を取得し、必要に応じてサーバーサイドオブジェクトを更新し、ユーザーがクリックした擬似タブに対応する出力を返します。に。これはJoe Chengのcollege scorecard applicationに基づいています(ページアンカーのクエリ文字列をスワップアウトするだけです)。また、URIでコード化しなければならない多数のユーザー定義の選択肢を持つ大きなデータセットをアプリがソースしているため、クエリー文字列を使ってそのルートに行くのではなく、新しい検索のたびにハードページの更新が開始されるため、入力を少し変更するたびにデータの再読み込み、前処理などが行われるユーザーエクスペリエンスはそれほど高くありません。

私はに実行している問題はsession$clientDataでその光沢のある店舗のみ初期 URIのハッシュであり、私はそれを更新するために、強制的に見つけた方法はありません、ユーザーがナビゲートする(invalidateLatereventReactive、またはobserveEvent付き) #summaryから#bleepから#blorpまでです。誰も前に同様の問題に遭遇しましたか?または、ハードページをリフレッシュせずにsession$clientDataオブジェクトをリフレッシュすることは可能ですか?

もう1つの方法は、隠しdivの場合はdisplay: none;という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") 
    }) 
}) 

答えて

0

私はちょうどカスタムの光沢のある入力を作成することによってこれを解明しました。基本的には、新しいShiny入力を反映するために空の/ hidden divを作成しました。その上には、Rstudio's instructionsごとにかなり標準的な入力バインディングがあります。私がしなければならなかった唯一の修正は、URIハッシュが変更されたときにいつでもコールバックをトリガーすることでした(この場合、ユーザーがいずれかのnavリンクをクリックした後)。ナビクリックにより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>