<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/dynamically-generated-shiny-ui/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.mango-solutions.com/wp/2016/12/dynamically-generated-shiny-ui/"> Mango Solutions » R Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><em>Gábor Csárdi — Mango Solutions<br>
Joe Cheng — RStudio</em></p>
<h2><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#introduction"></a>Introduction</h2>
<hr>
<p>It is not uncommon that the user interface of a Shiny application needs to be generated dynamically, based on data or program state. One typical use case that we encounter frequently is when the UI lets the user edit a variable number of records from a database.</p>
<p>Imagine that you have an employee database, where each employee can be assigned multiple roles. Each role also has additional data, for example, the proportion of work time the employee is expected to perform that role or a comment field. In a relational database, you would store this information in a <code>roles</code> table, where each row corresponds to one of the role assignments of an employee. When writing a Shiny app to edit the database, it makes sense to edit all roles of an employee on the same page: add or delete roles, or modify existing ones. This requires generating the user interface (UI) of the app dynamically, based on the database.</p>
<p><a target="_blank" rel="nofollow" href="https://i2.wp.com/www.mango-solutions.com/wp/wp-content/uploads/2016/11/screen1.png"><img alt="screen1" class="wp-image-6389" src="https://i2.wp.com/www.mango-solutions.com/wp/wp-content/uploads/2016/11/screen1-300x234.png?resize=300%2C234" data-recalc-dims="1"></a> <a target="_blank" rel="nofollow" href="https://i1.wp.com/www.mango-solutions.com/wp/wp-content/uploads/2016/11/screen2.png"><img alt="screen2" class="wp-image-6390" src="https://i2.wp.com/www.mango-solutions.com/wp/wp-content/uploads/2016/11/screen2-300x234.png?resize=300%2C234" data-recalc-dims="1"></a></p>
<h2>Requirements</h2>
<hr>
<p>We want our app to satisfy the following requirements:</p>
<ul>
<li>It must handle multiple employees, i.e. when a new employee is selected from the employee list, it should read in and show all current roles of that employee.</li>
<li>It must be able to edit existing roles of an employee, and then update the database.</li>
<li>It must be able to add new roles to an employee, and write the updated data to the database.</li>
<li>It must be able to delete roles from an employee, and write the updated data to the database.</li>
<li>It must be able to handle an arbitrary number of roles for an employee, including no roles at all.</li>
<li>It must only modify the database once the user clicks on the <code>Save</code> button.</li>
<li>It must have a <code>Cancel</code> button that discards all edits, and shows the employee roles as last read from the database.</li>
<li>The <code>Save</code> and <code>Cancel</code> buttons must be hidden if the employee data have not been changed.</li>
</ul>
<p>While these requirements are quite straightforward, they are not trivial to implement in Shiny. In the rest of this post we build an app that implements them.</p>
<h2>The app</h2>
<hr>
<div>
<pre>library(shiny)</pre>
</div>
<h3>The UI part of the app</h3>
<p>The UI definition of the app is quite straightforward, as most of the content will be dynamically generated. We will have the employee selection box on a side panel, and the roles of the selected employee on the main panel.</p>
<div>
<pre>ui &lt;- shinyUI(pageWithSidebar(
  headerPanel(&quot;Employee role database&quot;),
  sidebarPanel(
    selectInput(
      &quot;employee&quot;,
      &quot;Employee&quot;,
      choices = c(&quot;Jo Gee&quot;, &quot;John Doe&quot;)
    ),
    uiOutput(&quot;buttons&quot;)
  ),
  mainPanel(
    uiOutput(&quot;roles&quot;)
  )
))
</pre>
</div>
<p>For this simple example, we just list all employees here. In practice the employee names come from the database, of course.</p>
<p><code>buttons</code> will contain the <code>Add</code>, <code>Save</code> and <code>Cancel</code> buttons. The last two are dynamic, as they are only shown if the roles have changed. For simplicity we generate all three buttons dynamically.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#structure-of-the-app"></a>Structure of the app</h3>
<p>This app is different to others, as a significant part of it is event-driven. Many (most?) Shiny apps are purely reactive, i.e. they only contain recipes for how the different output values can be updated, and then it is up to Shiny to make sure that they are updated whenever they need to.</p>
<p>We found it hard to write this app the traditional way, mainly because the UI contains multiple action buttons that trigger dynamic UI changes, and also because the internal representation of the data must be changed without any output changes.</p>
<p>The app will have the following main components:</p>
<ul>
<li>We need to store the data that is on the user’s screen, and update it, as it changes. This will be in the <code>data</code> reactive value.</li>
<li>We need to store the data as in the database, to be able to compare it to the data under editing and show/hide the ‘Save’ and ‘Cancel’ buttons. We’ll use the <code>dbdata()</code> reactive for this.</li>
<li>We will use a <code>renderUI()</code> call to create the ‘Add’, ‘Cancel’ and ‘Save’ buttons, as needed.</li>
<li>We’ll attach events to the ‘Add’, ‘Cancel’ and ‘Save’ buttons, using <code>observeEvent()</code>.</li>
<li>We’ll use a <code>renderUI()</code> call to create the UI for the records, with a helper function, <code>createRecord()</code>, that creates a single record.</li>
</ul>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#triggering-ui-changes"></a>Triggering UI changes</h3>
<p>To trigger UI changes as needed, we introduce a reactive trigger constuct:</p>
<div>
<pre>makeReactiveTrigger &lt;- function() {
   rv &lt;- reactiveValues(a = 0)
   list(
     depend = function() {
       rv$a
       invisible()
     },
     trigger = function() {
       rv$a &lt;- isolate(rv$a + 1)
     }
   )
 }
</pre>
</div>
<p><code>makeReactiveTrigger</code> creates reactive triggers. A reactive trigger has two parts: </p>
<ol>
<li><code>$depend()</code> can be used within reactive expressions to declare that the reactive expression must be updated whenever the trigger sets off.</li>
<li><code>$trigger()</code> sets off the trigger.</li>
</ol>
<p>For the purpose of this post it is not very important to know how a reactive trigger works. It is sufficient to know that whenever it is <code>trigger()</code>-ed, all the <code>depend()</code>ent reactives are updated.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#the-server-function"><br>
</a>The <code>server</code> function</h3>
<p>We are ready to write the more complicated <code>server</code> function.</p>
<p>We will use the <code>data</code> reactive value to store the current values of the roles.<br>
<code>data</code> is updated whenever the input widgets change. (See later, when we create these widgets, in <code>createRecord()</code>.)</p>
<p>We assume that <code>data</code> is a data frame and each role corresponds to a row in it. For this simple app <code>data</code> has columns <code>id</code> and <code>role</code> only. Other metadata can be easily added as additional columns. The <code>id</code> field is a simple numeric id of the employee. For now we set <code>data</code> to <code>NULL</code>. It will be automatically updated to the first (=default) employee’s data when the app loads.</p>
<div>
<pre>server &lt;- function(input, output, session) {
  rvs &lt;- reactiveValues(data = NULL)
  db_dir &lt;- &quot;.&quot;
</pre>
<p>We’ll use <code>uiTrigger</code> to trigger a UI rebuild. This trigger is the heart of the app. We use it to control UI rebuilds for the records. <code>fileTrigger</code> is used to trigger an update of <code>dbdata()</code>, i.e. to (re)read the data from the database.</p>
<div>
<pre>  uiTrigger &lt;- makeReactiveTrigger()
  fileTrigger &lt;- makeReactiveTrigger()
</pre>
</div>
<p><code>dbdata()</code> provides the last version of the employee records, as in the database. It is updated whenever a new employee is selected (<code>input$employee</code>), and an update can also be triggered via <code>fileTrigger</code>.</p>
<p>For simplicity, we assume that each employee’s data is stored in a CSV file that is named according to the employee. It is easy to change this to a proper database query.</p>
<div>
<pre>  dbdata &lt;- reactive({
    cat(&quot;i reading input file\n&quot;)
    fileTrigger$depend()
    req(input$employee)
    filename &lt;- file.path(db_dir, paste0(input$employee, &quot;.csv&quot;))
    read.csv(filename, stringsAsFactors = FALSE)
  })
</pre>
</div>
<p>If new data is read from the database, then we also need to trigger a UI rebuild. For this we simply put an event handler on the <code>dbdata()</code> reactive. This runs every time the reactive is updated.</p>
<div>
<pre>  observeEvent(dbdata(), {
    rvs$data &lt;- dbdata()
    uiTrigger$trigger()
  })
</pre>
</div>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#dynamic-cancel-and-save-buttons"></a>Dynamic <code>Cancel</code> and <code>Save</code> buttons</h3>
<p>The <code>Add</code> button is always shown. The <code>Cancel</code> and <code>Save</code> buttons are only shown if <code>data</code> and <code>dbdata</code> are not the same.</p>
<div>
<pre>  dataSame &lt;- reactive({
    identical(rvs$data, dbdata())
  })

  output$buttons &lt;- renderUI({
    div(
      actionButton(inputId = &quot;add&quot;, label = &quot;Add&quot;),
      if (! dataSame()) {
        span(
          actionButton(inputId = &quot;cancel&quot;, label = &quot;Cancel&quot;),
          actionButton(inputId = &quot;save&quot;, label = &quot;Save&quot;,
                       class = &quot;btn-primary&quot;)
        )
      } else {
        span()
      }
    )
  })
</pre>
</div>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#add-reactivity"></a>Add reactivity</h3>
<p>So again, parts of this app are event-driven. We specify what should happen whenever the user presses the various action buttons, or edits the roles.</p>
<p>The first event we need to handle is adding a new role. We create a new id for it first, then just add it to the bottom of the data frame that holds the data. Then we trigger a UI rebuild.</p>
<div>
<pre>  observeEvent(input$add, {
    cat(&quot;i adding a new record\n&quot;)
    newid &lt;- if (nrow(rvs$data) == 0) {
      1L
    } else {
      max(as.integer(rvs$data$id)) + 1L
    }
    rvs$data &lt;- rbind(rvs$data, list(id = newid, role = &quot;&quot;))
    uiTrigger$trigger()
  })
</pre>
</div>
<p>When the <code>Cancel</code> button is hit, we need to restore the data from <code>dbdata()</code>. Then we trigger a UI rebuild. This is not always needed, but it is the simplest way to make sure that the UI shows the current data.</p>
<div>
<pre>  observeEvent(input$cancel, {
    cat(&quot;i cancelling edits\n&quot;)
    rvs$data &lt;- dbdata()
    uiTrigger$trigger()
  })
</pre>
</div>
<p>The <code>Save</code> button is also simple. We write out the file and make sure that the <code>dbdata()</code> reactive is updated, using <code>fileTrigger</code>. This will also trigger an unneccesary UI rebuild in the end, but we can live with that.</p>
<div>
<pre>  observeEvent(input$save, {
    cat(&quot;i saving to file\n&quot;)
    filename &lt;- file.path(db_dir, paste0(input$employee, &quot;.csv&quot;))
    write.csv(rvs$data, filename, quote = FALSE, row.names = FALSE)
    fileTrigger$trigger()
  })
</pre>
</div>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#the-main-dynamic-ui"></a>The main dynamic UI</h3>
<p>The next part is the main UI that contains the employee roles. We use <code>uiTrigger$depend()</code> to denote that this <code>renderUI</code> expression needs to run whenever a UI rebuild is triggered.</p>
<p>Note the use of <code>isolate</code>. We do not want <code>output$roles</code> to depend on <code>rvs$data</code> directly, because we only want to rebuild the UI after selected events, but not all data changes. E.g. if the user just edits a text input, no UI rebuild is needed.</p>
<p>We use <code>create_role</code> to create the UI and (possibly) the event wiring for each role. Its first argument is the widget id, a number between <code>1</code> and <code>n</code>, where <code>n</code> is the number of roles on the screen.</p>
<div>
<pre>  output$roles &lt;- renderUI({
    cat(&quot;i rebuild the UI\n&quot;)
    uiTrigger$depend()
    mydata &lt;- isolate(rvs$data)
    w &lt;- lapply(seq_len(nrow(mydata)), function(i) {
      create_role(i, mydata[i, ])
    })
    do.call(fluidRow, w)
  })
</pre>
</div>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#creating-the-ui-for-a-role"></a>Creating the UI for a role</h3>
<p>This is another key part of the app, and it is also the part that is easy to write incorrectly. <code>create_role</code> is a closure, a function that creates both a function and an environment to store data.</p>
<p>We need the environment to store the maximum number of widgets that were wired up with edit and delete events. We need this because in Shiny it is not (easily) possible to remove bindings (i.e. <code>observeEvent</code> triggers). So even if we rebuild the UI, and remove some elements, the previously created triggers will be still in effect, and recreating them will trigger duplicate events.</p>
<div>
<pre>  create_role &lt;- (function() {

    inited &lt;- 0

    function(wid, record) {
      w &lt;- div(wellPanel(
        textInput(
          paste0(&quot;inp-&quot;, wid),
          label = record$id,
          value = record$role
        ),
        actionButton(
          paste0(&quot;del-&quot;, wid),
          label = &quot;Delete&quot;,
          class = &quot;btn-danger&quot;
        )
      ))
</pre>
</div>
<p>So every time we build a widget with a given id (<code>wid</code>) number, we check if the widget’s events were already wired up, and only create new <code>observeEvent</code> triggers if they were not.</p>
<p>In other words, the newly built UI will reuse as many of the existing wired widgets as possible. <code>inited</code> stores the number of <code>wired</code> widgets and the ids of their inputs and delete buttons are <code>inp-x</code> and <code>del-x</code>, where <code>x</code> is a number between 1 and <code>inited</code>.</p>
<p>Note that editing the text input field does not trigger a UI rebuild, and this is intentional. We don’t want rebuilds just because the user has typed in something new in the input field.</p>
<div>
<pre>      if (wid > inited) {
        observeEvent(input[[paste0(&quot;inp-&quot;, wid)]], {
          rvs$data[wid, &quot;role&quot;] &lt;- input[[paste0(&quot;inp-&quot;, wid)]]
        })

        observeEvent(input[[paste0(&quot;del-&quot;, wid)]], {
          rvs$data &lt;- rvs$data[-wid, , drop = FALSE]
          uiTrigger$trigger()
        })
</pre>
</div>
<p>We need to update <code>inited</code> if we created wiring for a new widget.</p>
<div>
<pre>        inited &lt;&lt;- wid
      }

      w
    }
  })()
}
</pre>
</div>
<p>Note that here we create a function and call it immediately. The function itself creates and returns a function, which we assign to <code>create_role</code>. The effect of this is that every time we run <code>create_role</code>, it has access to the same <code>inited</code> variable, and updates it as needed. <code>inited</code> is in the parent environment of <code>create_role</code>.</p>
<p>Another non-obvious observation is that (by default) <code>observeEvent</code> evaluates the expression in the environment of its caller, which is the execution environment of the running <code>create_role</code> function. Execution environments are usually temporary, but in this case the <code>observeEvent</code> expression keeps a reference to it, so it is kept alive. This environment stores the value of <code>wid</code>, at the time the event handler was created. This way, every event handler expression refers to its own <code>wid</code> value.</p>
<p>We are now ready to start the app.</p>
<div>
<pre>shinyApp(ui, server, options = list(height = 1600))
</pre>
</div>
<h2><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#summary"></a>Summary</h2>
<hr>
<p>It took me (Gábor) a couple of attempts to write the first version of this small Shiny app. My initial, purely reactive (i.e. without reactive values and triggers) attempts all failed. Then Joe helped me simplify it, introduced the reactive trigger expression and gave me important insight about imperative and reactive apps.</p>
<p>While we expressed much of the app imperatively, it is important to understand that there isn’t an either/or relationship between imperative and reactive. What we want to do is identify which pieces of state need to be treated imperatively, and which can still be handled reactively.</p>
<p>The question you have to answer is, “Can this state be derived/computed from other state already represented in the system?” If so, it’s a strong candidate for being made into a reactive expression instead.</p>
<h2><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#exercises"></a>Exercises</h2>
<ol>
<li>Since we wrote the first version of the app, Shiny introduced <code>insertUI</code> and <code>removeUI</code>. These are probably better alternatives to our <code>create_role</code> closure. You need to know a tiny bit about CSS selectors to use them. Modify the app to use <code>insertUI</code> and <code>removeUI</code>.</li>
<li>(Hard.) Write a reusable Shiny module that encapsulates the complexity of this problem. Maybe the module could have the following parameters:
<ul>
<li>function to read in the data,</li>
<li>function to save the data,</li>
<li>function to build the UI of a single record, from the data, and an object id.</li>
</ul>
</li>
</ol>
<h2><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#feedback"></a>Feedback</h2>
<p>We would be very excited to hear about improvements or alternative solutions to this problem. Should you have one, please open an issue in the <a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny">https://github.com/MangoTheCat/dynshiny</a> repository. Thank you!</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/MangoTheCat/dynshiny/tree/master#try-the-app"></a>Try the app</h3>
<p>To try the app, go to <a target="_blank" rel="nofollow" href="https://mangothecat.shinyapps.io/dynshiny/">https://mangothecat.shinyapps.io/dynshiny/</a>.
</div>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.mango-solutions.com/wp/2016/12/dynamically-generated-shiny-ui/"> Mango Solutions » R Blog</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/naltBZdJxKU"></a></div>