shiny.router - a simple routing package for Shiny Dashboards
<blockquote>Update 22nd of October, 2018. We have updated shiny.router package and realeased it on <a href="https://cran.r-project.org/web/packages/shiny.router/index.html" target="_blank" rel="noopener noreferrer">R Cran</a> and <a href="https://github.com/Appsilon/shiny.router" target="_blank" rel="noopener noreferrer">GitHub</a>. <a href="https://appsilon.com/shiny-router-package/" target="_blank" rel="noopener noreferrer">Full post on shiny.router update with plenty of examples.</a></blockquote> <strong>The time has come</strong> to release the first of our internal tools we use on a regular basis when developing <a href="https://shiny.rstudio.com/" target="_blank" rel="noopener noreferrer">Shiny</a> apps for our customers. In just a few lines of code added to your project, you get a helpful routing mechanism that allows recreating a particular state of your app. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">make_router</span><span class="p">(</span> <span class="n">route</span><span class="p">(</span><span class="s2">"<your_app_url>/main"</span><span class="p">,</span> <span class="n">main_page_shiny_ui</span><span class="p">),</span> <span class="n">route</span><span class="p">(</span><span class="s2">"<your_app_url>/other"</span><span class="p">,</span> <span class="n">other_page_shiny_ui</span><span class="p">)</span> <span class="p">)</span></code></pre> </figure> If you’re in a hurry just go directly to the project’s page: <a href="https://appsilon.github.io/shiny.router/" target="_blank" rel="noopener noreferrer">https://appsilon.github.io/shiny.router/ </a> <h2 id="benefits-of-routing">Benefits of routing</h2> Routing has been around in web frameworks for a while. Since this was something we were missing in Shiny so much we developed this package to simplify our development. <strong>Firstly,</strong> it’s possible to share a link like <span style="text-decoration: underline;">http://your-app-url/stats/dashboard</span> and redirect a user to the specific state in-app. For instance, in our <a href="https://demo.appsilon.com/apps/router2/" target="_blank" rel="noopener noreferrer">shiny.router demo</a>, you can directly go to another page. <strong>Secondly,</strong> it’s easier to write clean code by separating UI into meaningful code blocks. <h2 id="how-do-you-integrate-it">How do you integrate it?</h2> First, make sure you have <strong>shiny.router</strong> dependency installed. This package is not yet available on CRAN, so you have to install it with <a href="https://github.com/hadley/devtools" target="_blank" rel="noopener noreferrer"><strong>devtools</strong></a>: <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="c1"># install.packages("devtools") </span><span class="n">devtools</span><span class="o">::</span><span class="n">install_github</span><span class="p">(</span><span class="s2">"Appsilon/shiny.router"</span><span class="p">)</span></code></pre> </figure> Second, you have to define a routing. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="c1"># Creates router. We provide routing path and UI for this page. </span><span class="n">router</span> <span class="o"><-</span> <span class="n">make_router</span><span class="p">(</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">root_page</span><span class="p">),</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/other"</span><span class="p">,</span> <span class="n">other_page</span><span class="p">)</span> <span class="p">)</span></code></pre> </figure> This will create 2 reactive links: <ol><li><span style="text-decoration: underline;">http://your-app-url</span> redirecting to the <strong>Root page</strong> and</li><li><span style="text-decoration: underline;">http://your-app-url/other</span> redirecting to <b>Other pages</b> in your app.</li></ol> The first passed argument is also a default redirection for all invalid links(“/” in this case). You can also specify it explicitly via the <strong>“default”</strong> argument. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="c1"># Creates router. We provide routing path and UI for this page. </span><span class="n">router</span> <span class="o"><-</span> <span class="n">make_router</span><span class="p">(</span> <span class="n">default</span> <span class="o">=</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/home"</span><span class="p">,</span> <span class="n">home_page</span><span class="p">),</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">root_page</span><span class="p">),</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/other"</span><span class="p">,</span> <span class="n">other_page</span><span class="p">)</span> <span class="p">)</span></code></pre> </figure> Next, make sure you bind and run your <strong>“router”</strong> object properly in your Shiny app source code. <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="c1"># Creat output for our router in main UI of Shiny app. </span><span class="n">ui</span> <span class="o"><-</span> <span class="n">shinyUI</span><span class="p">(</span><span class="n">fluidPage</span><span class="p">(</span> <span class="c1"># This line is important! </span> <span class="n">router_ui</span><span class="p">()</span> <span class="p">))</span> <br><span class="c1"># Plug router into Shiny server. </span><span class="n">server</span> <span class="o"><-</span> <span class="n">shinyServer</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># This line is important! </span> <span class="n">router</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span> <span class="p">})</span></code></pre> </figure> Now it’s time for a live demo. Try clicking “Page” and “Other” menu links: <iframe src="https://demo.appsilon.com/apps/router2/_w_3f10f846/#!/" width="100%" height="250" frameborder="0" scrolling="no"></iframe> Here’s the complete code, if you want to try it out by yourself: <figure class="highlight"> <pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="n">shiny</span><span class="p">)</span> <span class="c1">#devtools::install_github("Appsilon/shiny.router") </span><span class="n">library</span><span class="p">(</span><span class="n">shiny.router</span><span class="p">)</span> <br><span class="c1"># This generates menu in user interface with links. </span><span class="n">menu</span> <span class="o"><-</span> <span class="p">(</span> <span class="n">tags</span><span class="o">$</span><span class="n">ul</span><span class="p">(</span> <span class="n">tags</span><span class="o">$</span><span class="n">li</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">class</span> <span class="o">=</span> <span class="s2">"item"</span><span class="p">,</span> <span class="n">href</span> <span class="o">=</span> <span class="s2">"/"</span><span class="p">,</span> <span class="s2">"Page"</span><span class="p">)),</span> <span class="n">tags</span><span class="o">$</span><span class="n">li</span><span class="p">(</span><span class="n">a</span><span class="p">(</span><span class="n">class</span> <span class="o">=</span> <span class="s2">"item"</span><span class="p">,</span> <span class="n">href</span> <span class="o">=</span> <span class="s2">"/other"</span><span class="p">,</span> <span class="s2">"Other"</span><span class="p">))</span> <span class="p">)</span> <span class="p">)</span> <br><span class="c1"># This creates UI for each page. </span><span class="n">page</span> <span class="o"><-</span> <span class="k">function</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span> <span class="p">{</span> <span class="n">div</span><span class="p">(</span> <span class="n">menu</span><span class="p">,</span> <span class="n">titlePanel</span><span class="p">(</span><span class="n">title</span><span class="p">),</span> <span class="n">p</span><span class="p">(</span><span class="n">content</span><span class="p">)</span> <span class="p">)</span> <span class="p">}</span> <br><span class="c1"># Both sample pages. </span><span class="n">root_page</span> <span class="o"><-</span> <span class="n">page</span><span class="p">(</span><span class="s2">"Home page"</span><span class="p">,</span> <span class="s2">"Welcome on sample routing page!"</span><span class="p">)</span> <span class="n">other_page</span> <span class="o"><-</span> <span class="n">page</span><span class="p">(</span><span class="s2">"Some other page"</span><span class="p">,</span> <span class="s2">"Lorem ipsum dolor sit amet"</span><span class="p">)</span> <br><span class="c1"># Creates router. We provide routing path and UI for this page. </span><span class="n">router</span> <span class="o"><-</span> <span class="n">make_router</span><span class="p">(</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">root_page</span><span class="p">),</span> <span class="n">route</span><span class="p">(</span><span class="s2">"/other"</span><span class="p">,</span> <span class="n">other_page</span><span class="p">)</span> <span class="p">)</span> <br><span class="c1"># Creat output for our router in main UI of Shiny app. </span><span class="n">ui</span> <span class="o"><-</span> <span class="n">shinyUI</span><span class="p">(</span><span class="n">fluidPage</span><span class="p">(</span> <span class="n">router_ui</span><span class="p">()</span> <span class="p">))</span> <br><span class="c1"># Plug router into Shiny server. </span><span class="n">server</span> <span class="o"><-</span> <span class="n">shinyServer</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span> <span class="p">{</span> <span class="n">router</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span> <span class="p">})</span> <br><span class="c1"># Run server in a standard way. </span><span class="n">shinyApp</span><span class="p">(</span><span class="n">ui</span><span class="p">,</span> <span class="n">server</span><span class="p">)</span></code></pre> </figure> <h2 id="next-steps">Next steps</h2> You might be wondering how we managed to make this nice-looking demo. This is a small preview of our next package using <a href="https://demo.appsilon.com/apps/visuarisk/" target="_blank" rel="noopener noreferrer"><strong>SemanticUI</strong></a>. You can find it on our <a href="https://github.com/Appsilon/shiny.semantic" target="_blank" rel="noopener noreferrer"><strong>Github</strong></a>. <strong>Side Note!</strong> <em>You will have to install it to run a second repo example.</em> Please stay tuned for our next blog post.