Now that I have moved over to the corporate world, I have been doing a lot of development in R and RShiny. If you have not used it before, RShiny is an amazing tool for quickly creating scientific dashboards that are data-driven. With a little bit of knowledge of R and Web development, you can create some stunning data-driven documents in this framework without having to worry too much about how the front-end and back-end of the application interact. You can learn more about it here: https://shiny.rstudio.com/tutorial/
While it is amazing, there are some drawback that require you to look under the hood of Shiny. One example is the conditionalPanel (https://shiny.rstudio.com/reference/shiny/latest/conditionalPanel.html). This works as follows:
conditionalPanel("output.test == 1", { div(h3("test")) })
This will produce the following:
<div data-display-if="output.test == 1" data-ns-prefix=""> <div> <h3>test</h3> </div> </div>
Which is good for most applications. However, recently I was having a problem creating a conditional menu item in the Shiny sidebar. For example, I had the following code:
conditionalPanel("output.test == 1", { menuItem( "Data Entry", tabName = "data_entry", icon = icon("upload") ) })
Which produced:
<div data-display-if="output.test == 1" data-ns-prefix=""> <li> <a href="#shiny-tab-data_entry" data-toggle="tab" data-value="data_entry"> <i class="fa fa-upload"></i> <span>Data Entry</span> </a> </li> </div>
As you can see, this wraps the list item tags (li) in a conditional div. This caused havoc in the UI as the list item was now being rendered after the div. Luckily, it is very easy to override the output of RShiny applications; all RShiny outputs produce a well structured list whose attributes are easily editable. For example, what I desired was the “data-display-if” code to be on the li tag above. This was easily achievable with the following code snippet:
conditionalMenuItem <- function(label,tabName,iconName,condition) { t <- menuItem( label, tabName = tabName, icon = icon(iconName) ) t$attribs <- list('data-display-if'=condition,'data-ns-prefix'='') t }
Which produces:
<li data-display-if="output.test == 1" data-ns-prefix=""> <a href="#shiny-tab-data_entry" data-toggle="tab" data-value="data_entry"> <i class="fa fa-upload"></i> <span>Data Entry</span> </a> </li>
As you can see, overriding the attribs menuItem output makes it possible to place the condition on the list item, removing the need for the conditionalPanel. Overall, this creates a smoother UI for the user and less headache making UI elements line up. You can also edit the attribs of any of the items in the list that is returned by menuItem, just look at the children variable which stores nested elements in a nested list with an similar structure of attribs, names, and children. These can all be edited in a wrapping function as we did above. What is exciting about this is that all shiny elements have a similar output; you can easily create a conditionalImg, conditionalPlot, or conditionalShinyElement through simple modifications.