<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/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/"></div></div><div><a data-url="https://www.r-bloggers.com/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/" data-counturl="https://www.r-bloggers.com/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/" data-count="horizontal" data-text="How to write a useful htmlwidgets in R: tips and walk-through a real example" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://deanattali.com/blog/htmlwidgets-tips/"> Dean Attali's R Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I’d like to share some tips and recommendations on building htmlwidgets, based on my own learning experience while creating <a target="_blank" href="https://github.com/daattali/timevis"><code>timevis</code></a>. These tips are mostly concerned with making your htmlwidget more useful and user friendly. In this post, every tip I provide will be followed by an actual code walk-through so that you can see it applied in a real example.</p>
<p>Keep in mind that two weeks ago<sup><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#footnote">*</a></sup> I was still an htmlwidgets virgin, so I should in no way be considered an authority figure on the subject. But I did spend a long time trying to solve all sorts of problems I ran into and I ended up making an htmlwidget that has a lot of useful functionality that isn’t documented anywhere, so I’m hoping that some of the things I learned can be useful for others as well.</p>
<p>The last two tips (7 and 8) are by far the most useful, but I kept them at the end because they’re also the most complex.</p>
<h2>Table of contents</h2>
<ul>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#background">Background</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#starting-point">Starting point for this “tutorial”</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#rendervalue-x-name">Tip 1: Use sensible parameter name in <code>renderValue(x)</code> instead of <code>x</code></a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#custom-html">Tip 2: Add custom HTML to the widget</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#dataframeToD3">Tip 3: Convert a data frame to a D3-compatible data structure in R</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#rendervalue-multiple-times">Tip 4: The <code>renderValue()</code> function gets called every time the R binding function gets called</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#init-once">Tip 5: Make sure any one-time initialization code gets run only once</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#shinyMode">Tip 6: Find out if the widget is in a shiny app or not with <code>HTMLWidgets.shinyMode</code></a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#widget-to-r-data">Tip 7a: Pass data from the widget to R</a>
<ul>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#javascript-to-r-handler">Tip 7b: Use a custom function to convert the JavaScript data into an R object</a></li>
</ul>
</li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#api">Tip 8: Add API functions to lets users programmatically interact with the widget</a>
<ul>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#api-basic">Tip 8a: Basic implementation</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#api-abstract">Tip 8b: Abstracting the code to make it easier to add new API functions</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#api-chain">Tip 8c: Support chaining API functions with pipes (<code>%>%</code>)</a></li>
<li><a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#api-not-just-shiny">Tip 8d: Make API functions work outside of Shiny too</a></li>
</ul>
</li>
</ul>
<h2>Background</h2>
<p>For those who don’t know, <a target="_blank" href="http://www.htmlwidgets.org/"><code>htmlwidgets</code></a> is a handy package that lets you bring functionality from 3rd-party JavaScript libraries into R. This can be especially useful when wanting to use new types of visualizations in Shiny apps.</p>
<p>Last year, when asked a question about htmlwidgets, <a target="_blank" href="https://github.com/timelyportfolio/sweetalertR/issues/1#issuecomment-123564079">my response</a> was that <em>“I’m a bit embarrassed to admit that I haven’t actually looked into htmlwidgets yet”</em>. Almost a year later, in useR 2016 conference, I had a chat with <a target="_blank" href="https://github.com/ramnathv">Ramnath Vaidyanathan</a>. And, again, I had to embarrassingly admit that I still don’t really know how htmlwidgets works, but this time I had the added impact of saying it directly to one of the package’s co-authors. In that moment I decided that it’s time for me to learn htmlwigets.</p>
<p>So a few weeks later I set out to write my first htmlwidget. Even though it was meant to be purely a learning exercise, I wanted it to at least be minimally useful so that it’s not a waste of time. I started looking at a ton of JavaScript visualization libraries and checked each one to see if it already exists in R. This was a harder task than I imagined, but I eventually deicded to turn the <a target="_blank" href="http://visjs.org/docs/timeline/">vis.js Timeline module</a> into an R htmlwidgets, and hence my newest package <a target="_blank" href="https://github.com/daattali/timevis">timevis</a> was born.</p>
<p>I’m not going to cover the basics of how to write htmlwidgets (if you just want to learn how to write htmlwidgets, the <a target="_blank" href="http://www.htmlwidgets.org/develop_intro.html">official documentation</a> is great). What this post will do is describe some things that I implemented in timevis that go beyond the basics and that I think can be applied to many htmlwidgets in order to make them much more useful. To help make these ideas more concrete, I created a minimal barebones htmlwidget that we will improve upon throughout this post.</p>
<p>I would like to repeat and stress that I’m very new to htmlwidgets myself so it’s entirely possible that people smarter than myself would disagree with some of my ideas. But I still think it’s useful to go through this list I made and see if any of my lessons make sense in your case.</p>
<h2>Starting point for this “tutorial”</h2>
<p>I created a GitHub repository with a minimal functioning <code>timevis</code> htmlwidget called <a target="_blank" href="https://github.com/daattali/timevisBasic"><code>timevisBasic</code></a>. Throughout this tutorial, I will give you tips on how to improve htmlwidgets, and we will see them in action by incrementally adding those ideas to <code>timevisBasic</code>.</p>
<p>I recommend you take a quick look at <code>timevisBasic</code> before continuing to see what our starting point is. At the very least you should read the <a target="_blank" href="https://github.com/daattali/timevisBasic#readme">README</a> and just take a glance at the very simple <a target="_blank" href="https://github.com/daattali/timevisBasic/blob/master/R/timevisBasic.R">R source file</a> and <a target="_blank" href="https://github.com/daattali/timevisBasic/blob/master/inst/htmlwidgets/timevisBasic.js">JavaScript source file</a>.</p>
<h2>Tip 1: Use a sensible parameter name in <code>renderValue(x)</code> instead of <code>x</code></h2>
<p>I’ll start with a very simple tip. The htmlwidgets docs tell you to define the <code>renderValue</code> JavaScript function as</p>
<div>
<pre><code><span>renderValue</span><span>:</span> <span>function</span><span>(</span><span>x</span><span>)</span> <span>{</span> <span>...</span> <span>}</span>
</code></pre>
</div>
<p>Now, this <code>x</code> variable is actually very useful. It contains all the values that are passed in from R to the widget itself. So you often end up referring to <code>x</code> a lot in your code. I have <a target="_blank" href="https://github.com/daattali/timevis/commit/7bd3e7390256a7617e3642078a94d301062ab628">a commit</a> that has the sole purpose of renaming <code>x</code> to <code>opts</code>, and I think you should do that too, for two main reasons. First, <code>opts</code> is a much more descriptive name than <code>x</code> and it tells you that it holds all the different widget options. Second, I’m always against using any variable name that is only one or two characters long, because it makes it very difficuly to search for it.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>: <a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name#diff">https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name#diff</a></p>
<h2>Tip 2: Add custom HTML elements to your widget</h2>
<p>The official htmlwidgets documentation <a target="_blank" href="http://www.htmlwidgets.org/develop_advanced.html#custom-widget-html">tells us</a> that the widget will be “housed” inside a <code>&lt;div></code> tag by default. You can define a special function if you want the widget to be enclosed by a different tag, for example</p>
<div>
<pre><code><span>timevis_html</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>style</span><span>,</span><span> </span><span>class</span><span>,</span><span> </span><span>...</span><span>){</span><span>
</span><span>tags</span><span>$</span><span>span</span><span>(</span><span>id</span><span> </span><span>=</span><span> </span><span>id</span><span>,</span><span> </span><span>class</span><span> </span><span>=</span><span> </span><span>class</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>This will change the enclosing tag of the widget to be a <code>&lt;span></code> instead.</p>
<p>But what’s more interesting is that you can also use this idea to add HTML elements that are not part of the JavaScript library into the widget. For example, I wanted to add zoom in and zoom out buttons into my timevis widget (the 3rd-party JavaScript library I use does not have zooming buttons) so I added this R function:</p>
<div>
<pre><code><span>timevis_html</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>style</span><span>,</span><span> </span><span>class</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span>tags</span><span>$</span><span>div</span><span>(</span><span>
</span><span>id</span><span> </span><span>=</span><span> </span><span>id</span><span>,</span><span> </span><span>style</span><span> </span><span>=</span><span> </span><span>style</span><span>,</span><span> </span><span>class</span><span> </span><span>=</span><span> </span><span>class</span><span>,</span><span>
</span><span>htmltools</span><span>::</span><span>div</span><span>(</span><span>
</span><span>style</span><span> </span><span>=</span><span> </span><span>&quot;position: absolute;&quot;</span><span>,</span><span>
</span><span>htmltools</span><span>::</span><span>tags</span><span>$</span><span>button</span><span>(</span><span>&quot;+&quot;</span><span>),</span><span>
</span><span>htmltools</span><span>::</span><span>tags</span><span>$</span><span>button</span><span>(</span><span>&quot;-&quot;</span><span>)</span><span>
</span><span>)</span><span>
</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>You can see the actual final code I used in <code>timevis</code> <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/R/timevis.R#L439-L459">here</a>.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>: <a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name...tip2-custom-html#diff">https://github.com/daattali/timevisBasic/compare/tip1-rendervalue-x-name…tip2-custom-html#diff</a></p>
<h2>Tip 3: Convert a data frame to a D3-compatible data structure in R</h2>
<p>As the htmlwidgets docs <a target="_blank" href="http://www.htmlwidgets.org/develop_advanced.html#htmlwidgets.dataframetod3">point out</a>, R data frames are represented in “long” form (an array of named vectors) whereas D3 often requires data to be in “wide” form (an array of objects each of which includes all names and values). In order to transform an R data frame to d3 format, htmlwidgets provides us with the <code>HTMLWidgets.dataframeToD3()</code> JavaScript function. This should usually be good enough, but in my particular case it didn’t work quite right because it converts any <code>NA</code> values in the data frame into <code>null</code> values in JavaScript, which presented errors with the specific library I’m using. My solution was to implement my own <code>dataframeToD3()</code> function in R:</p>
<div>
<pre><code><span>dataframeToD3</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>df</span><span>)</span><span> </span><span>{</span><span>
</span><span>if</span><span> </span><span>(</span><span>missing</span><span>(</span><span>df</span><span>)</span><span> </span><span>||</span><span> </span><span>is.null</span><span>(</span><span>df</span><span>))</span><span> </span><span>{</span><span>
</span><span>return</span><span>(</span><span>list</span><span>())</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>is.data.frame</span><span>(</span><span>df</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;timevis: the input must be a dataframe&quot;</span><span>,</span><span> </span><span>call.</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span><span>}</span><span>
</span><span>row.names</span><span>(</span><span>df</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>NULL</span><span>
</span><span>apply</span><span>(</span><span>df</span><span>,</span><span> </span><span>1</span><span>,</span><span> </span><span>function</span><span>(</span><span>row</span><span>)</span><span> </span><span>as.list</span><span>(</span><span>row</span><span>[</span><span>!</span><span>is.na</span><span>(</span><span>row</span><span>)]))</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>This function takes in a regular R data frame and converts it to a format that is compatible with D3, and it specifically drops any <code>NA</code> values. You can see it in use in timevis <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/R/timevis.R#L314">here</a>; I simply convert any input data to wide format using this function, and pass that data to JavaScript.</p>
<p>Since the d3 representation of a data frame is much more verbose, this results in bigger data to transfer over the network, so I don’t generally recommend doing this transformation in R unless you really need to (as in my case, where using the JavaScript method provided by HTMLWidgets was not sufficient).</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip2-custom-html...tip3-dataframeToD3#diff">https://github.com/daattali/timevisBasic/compare/tip2-custom-html…tip3-dataframeToD3#diff</a></p>
<h2>Tip 4: The <code>renderValue()</code> function gets called every time the R binding function gets called</h2>
<p>The <code>renderValue()</code> function, which is responsible for creating the JavaScript widget based on some data that was passed in from R, gets called every time the R binding function is called. For example, in my package whenever <code>timevis()</code> is called in R, the <code>renderValue()</code> function is called in JavaScript. This may sound trivial, but I didn’t see it explicitly spelled out in the documentation and I think it’s important to understand.</p>
<p>What this means is that if you create your widget based on a reactive value in a shiny app, then every time the reactive value updates, the widget’s <code>renderValue()</code> will be called again. It might not be a problem for you, but it’s good to be aware of that because you should make a conscious decision on what happens when the widget’s “initialization” code (<code>renderValue()</code>) is run multiple times.</p>
<p>For example, suppose we want to render a timevis widget and use a dynamic height based on an input control in Shiny. You might use the following snippet in the shiny server code:</p>
<div>
<pre><code><span>data</span><span> </span><span>&lt;-</span><span> </span><span>data.frame</span><span>(</span><span>...</span><span>)</span><span>
</span><span>output</span><span>$</span><span>vis</span><span> </span><span>&lt;-</span><span> </span><span>renderTimevis</span><span>({</span><span>
</span><span>timevis</span><span>(</span><span>data</span><span>,</span><span> </span><span>height</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>height</span><span>)</span><span>
</span><span>})</span><span>
</span></code></pre>
</div>
<p>There are two things that can happen every time <code>timevis()</code> is called: either the given data is <em>added</em> to the current widget, or it <em>replaces</em> the current widget.</p>
<h4>1. Add new data to the widget</h4>
<p>Using the following JavaScript code, every time the height input changes, more data will be added to the widget.</p>
<div>
<pre><code><span>factory</span> <span>:</span> <span>function</span><span>(</span><span>el</span><span>,</span> <span>width</span><span>,</span> <span>height</span><span>)</span> <span>{</span>
  <span>var</span> <span>timeline</span> <span>=</span> <span>new</span> <span>vis</span><span>.</span><span>Timeline</span><span>(</span><span>document</span><span>.</span><span>getElementById</span><span>(</span><span>el</span><span>.</span><span>id</span><span>),</span> <span>[],</span> <span>{});</span>
  
  <span>return</span> <span>{</span>
    <span>renderValue</span><span>:</span> <span>function</span><span>(</span><span>opts</span><span>)</span> <span>{</span>
      <span>timeline</span><span>.</span><span>itemsData</span><span>.</span><span>add</span><span>(</span><span>opts</span><span>.</span><span>items</span><span>);</span>
    <span>}</span>
  <span>}</span>
<span>}</span>
</code></pre>
</div>
<h4>2. Replace existing widget data with new data</h4>
<p>When I first made <code>timevis</code>, I didn’t consciously think about what happens when the render function is called multiple times, and I implemented the previous code. This resulted in <a target="_blank" href="https://github.com/daattali/timevis/issues/3">a bug</a> where every time the widget got re-rendered, the old data was not removed. Of course the fix was simple, in my case all I had to do was clear the current data from the widget before adding the new data. I simply added <code>timeline.itemsData.clear();</code> to the beginning of the <code>renderValue</code> function. Of course the exact code you’ll have to run will depend on the JavaScript library you’re bringing into R, but hopefully you get the idea.</p>
<p>In some visualizations it might make more sense to keep the old data and just add new data, so you should do whatever makes the most sense for your library.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip3-dataframeToD3...tip4-rendervalue-multiple-times#diff">https://github.com/daattali/timevisBasic/compare/tip3-dataframeToD3…tip4-rendervalue-multiple-times#diff</a></p>
<h2>Tip 5: Make sure any one-time initialization code gets run only once</h2>
<p>The widget initialization code should live in the <code>renderValue()</code> JavaScript function. Since that function can get called multiple times (as explained above), it’s a good idea to ensure that as many parts as possible are only initialized once instead of getting defined every single time the function gets called.</p>
<p>For example, in <code>timevis</code> I have some buttons (zoom buttons as mentioned <a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#custom-html">above</a>) that need to register click listeners, but that should only happen once. In order to do that, I define a boolean flag <code>initialized</code>, set it to <code>true</code> the first time the widget code runs, and only run initialization code if it’s <code>false</code>. Code example:</p>
<div>
<pre><code><span>factory</span> <span>:</span> <span>function</span><span>(</span><span>el</span><span>,</span> <span>width</span><span>,</span> <span>height</span><span>)</span> <span>{</span>
  <span>var</span> <span>initialized</span> <span>=</span> <span>false</span><span>;</span>
  
  <span>return</span> <span>{</span>
    <span>renderValue</span><span>:</span> <span>function</span><span>(</span><span>opts</span><span>)</span> <span>{</span>
      <span>if</span> <span>(</span><span>!</span><span>initialized</span><span>)</span> <span>{</span>
        <span>initialized</span> <span>=</span> <span>true</span><span>;</span>
        <span>// Code to set up event listeners and anything else that needs to run just once</span>
      <span>}</span>
    <span>}</span>
  <span>}</span>
<span>}</span>
</code></pre>
</div>
<p>You can see this code pattern in action <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/inst/htmlwidgets/timevis.js#L26-L38">in timevis</a>.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip4-rendervalue-multiple-times...tip5-init-once#diff">https://github.com/daattali/timevisBasic/compare/tip4-rendervalue-multiple-times…tip5-init-once#diff</a></p>
<h2>Tip 6: Find out if the widget is in a shiny app or not with <code>HTMLWidgets.shinyMode</code></h2>
<p>htmlwidgets can be rendered in a few different contexts: they can be embedded in Rmarkdown documents, viewed as a standalone in RStudio or in a browser, or they can be included in Shiny apps. It may be beneficial to know whether the widget is currently inside a shiny app or not (for example, if you want the widget to interact with Shiny). You can access the variable <code>HTMLWidgets.shinyMode</code> in JavaScript code to find out if the current widget is in a Shiny context or not.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip5-init-once...tip6-shinyMode#diff">https://github.com/daattali/timevisBasic/compare/tip5-init-once…tip6-shinyMode#diff</a></p>
<h2>Tip 7a: Pass data from the widget to R</h2>
<p>The native flow of information in an htmlwidget is from R to the widget. The widget cannot natively pass information back to R. But when you include an htmlwidget inside a Shiny app, you might want to be able to access some data from the widget in your Shiny app. This can be done using the typical method of passing information from JavaScript to R using <code>Shiny.onInputChange()</code>. If you’re not familiar with this method, you can learn about it <a target="_blank" href="https://github.com/daattali/advanced-shiny/tree/master/message-javascript-to-r">in my previous post</a>.</p>
<p>This usually involves setting up some event listener in JavaScript for an event that you may be interested in, calling <code>Shiny.onInputChange()</code> in the listener callback, and listening for that data in R through the <code>input</code> variable. For example, in <code>timevis</code> I wanted the user to know what items have been selected in the widget, so I added this simple code:</p>
<div>
<pre><code><span>timeline</span><span>.</span><span>on</span><span>(</span><span>'select'</span><span>,</span> <span>function</span> <span>(</span><span>properties</span><span>)</span> <span>{</span>
  <span>Shiny</span><span>.</span><span>onInputChange</span><span>(</span><span>elementId</span> <span>+</span> <span>&quot;_selected&quot;</span><span>,</span> <span>properties</span><span>.</span><span>items</span><span>);</span>
<span>});</span>
</code></pre>
</div>
<p>What that code does is: every time an item gets selected (<code>timeline.on('select', ...)</code>), we pass the data (<code>properties.items</code>) to R, and it will be accessible as <code>input$&lt;elementId>_selected</code>. For completeness, I also pass this data to R when the app first starts, so that the user will be able to access that variable even before any selection is being made:</p>
<div>
<pre><code><span>Shiny</span><span>.</span><span>onInputChange</span><span>(</span><span>elementId</span> <span>+</span> <span>&quot;_selected&quot;</span><span>,</span> <span>timeline</span><span>.</span><span>getSelection</span><span>());</span>
</code></pre>
</div>
<p>You can see this code in the <code>timevis</code> source code <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/inst/htmlwidgets/timevis.js#L43-L53">here</a>. You’ll also notice that I wrapped this code inside a check for <code>if (HTMLWidgets.shinyMode) {...}</code> since it only makes sense to pass data back to R when you’re in a Shiny app.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip6-shinyMode...tip7a-widget-to-r-data#diff">https://github.com/daattali/timevisBasic/compare/tip6-shinyMode…tip7a-widget-to-r-data#diff</a></p>
<h3>Tip 7b: Use a custom function to convert the JavaScript data into an R object</h3>
<p>This is actually purely a Shiny issue rather than an htmlwidgets issue (you can learn more about it in my <a target="_blank" href="https://github.com/daattali/advanced-shiny/tree/master/javascript-to-r-handler">previous post</a>), but it can come up when developing a widget so I will mention it here.</p>
<p>When using <code>Shiny.onInputChange(name, data)</code>, you are passing in a JavaScript object (<code>data</code>) and expect it to get converted to an R object (<code>input$name</code>). This conversion happens by serializing and deserializing the data to and from JSON. Usually <code>input$name</code> will look exactly like you’d expect it to, but it is possible for the conversion process to not do exactly what you want. Alternatively, you may just want to alter the data slightly in R before presenting it to Shiny.</p>
<p>This is where the <code>shiny::registerInputHandler()</code> function comes in: it allows you to transform the data passed in from JavaScript before it gets used as <code>input$</code>. For example, suppose you use <code>Shiny.onInputChange(&quot;myobj&quot;, value)</code> to send a value from JavaScript to R, but you want <code>input$myobj</code> to be automatically converted into a list. There are two simple steps you’d need to follow:</p>
<ol>
<li>
<p>In JavaScript, change <code>Shiny.onInputChange(&quot;myobj&quot;, value)</code> to <code>Shiny.onInputChange(&quot;myobj:mylist&quot;, value)</code>. Notice that we append <code>:&lt;type></code> to the name of the object. This specifices the type of object that is being passed to Shiny, so that Shiny will know what handler to call when deserializing its value.</p>
</li>
<li>
<p>In R, define the following function:</p>
</li>
</ol>
<p><code>r<br>
  shiny::registerInputHandler(&quot;mylist&quot;, function(data, ...) {<br>
    list(data)<br>
  }, force = TRUE)<br>
 </code></p>
<p>Now if you access <code>input$myobj</code> in shiny, the value will be wrapped in a list. Of course this particular example isn’t terribly useful, but this principle can be applied in real apps. For example, you can see how <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/R/utils.R#L2-L7">I used it</a> in <code>timevis</code> to fix an issue where the timeline data I wanted to pass to Shiny was getting flattened to a vector by default and I wanted it to be a data.frame instead. You’ll also see that I put that code inside <code>.onLoad</code>, which I’m not completely sure is the correct place for that code, so let me know if you have any thoughts on that.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip7a-widget-to-r-data...tip7b-javascript-to-r-handler#diff">https://github.com/daattali/timevisBasic/compare/tip7a-widget-to-r-data…tip7b-javascript-to-r-handler#diff</a></p>
<h2>Tip 8: Add API functions to lets users programmatically interact with the widget</h2>
<p>I saved this one for last because it’s the most involved suggestion, but it’s also the one that will give your htmlwidget the greatest benefit.</p>
<p>You can make a decent htmlwidget by only implementing the JavaScript <code>renderValue()</code> function, but you can make a much more useful widget by also allowing the user to interact with the widget programmatically after its creation. Most JavaScript libraries provide some sort of a constructor function that builds a widget (this is what you’d call inside <code>renderValue()</code>), as well as other functions that let you interact with the widget (aka an API). I think it’s always a good idea to give the user an interface to this API, as it will make your widget more powerful.</p>
<p>The exact way you’d implement an API to your widget depends on the API available by the JavaScript library you’re using, but I believe I came up with a good generic framework for adding API functions that can be used by other widgets.</p>
<h3>Tip 8a: Basic implementation</h3>
<p>Let’s walk through implementing a real API function in a real htmlwidget (we’ll use <code>timevisBasic</code> of course, which closely mimics the real <code>timevis</code> package). If you look at the <a target="_blank" href="http://visjs.org/docs/timeline/#Methods">documentation for vis.js</a> (which is the JavaScript library I used to port the timeline widget), you’ll see there are many API functions available to manipulate an existing timeline widget. Let’s pick one of them at random, say <code>setWindow()</code>, and see how we can add a <code>setWindow()</code> function to our R htmlwidget package.</p>
<p>Notice that <code>setWindow()</code> has two required arguments <code>start</code> and <code>end</code>, and one optional argument <code>options</code>. Essentially what we want to do is be able to call a function in R, supply it with those arguments as well as an ID (the widget ID), and have it call the library’s <code>setWindow()</code> method. We will rely on the system that Shiny provides for passing data from R to JavaScript using <code>sendCustomMessage()</code>; if you aren’t familiar with that function, you can learn about it in <a target="_blank" href="https://github.com/daattali/advanced-shiny/tree/master/message-r-to-javascript">my previous post about it</a>.</p>
<h4>R code</h4>
<p>The first thing we need to do is define an R function that accepts those four parameters and passes them to JavaScript. I’ll use <code>timevis:setWindow</code> as the name of the message – you don’t have to namespace the messages like that, but I prefer to do that in order to minimize the chance of having name collisions.</p>
<div>
<pre><code><span>setWindow</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>start</span><span>,</span><span> </span><span>end</span><span>,</span><span> </span><span>options</span><span>)</span><span> </span><span>{</span><span>
</span><span>message</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>id</span><span> </span><span>=</span><span> </span><span>id</span><span>,</span><span> </span><span>start</span><span> </span><span>=</span><span> </span><span>start</span><span>,</span><span> </span><span>end</span><span> </span><span>=</span><span> </span><span>end</span><span>)</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>missing</span><span>(</span><span>options</span><span>))</span><span> </span><span>{</span><span>
</span><span>message</span><span>[</span><span>'options'</span><span>]</span><span> </span><span>&lt;-</span><span> </span><span>options</span><span>
</span><span>}</span><span>
</span><span>session</span><span> </span><span>&lt;-</span><span> </span><span>shiny</span><span>::</span><span>getDefaultReactiveDomain</span><span>()</span><span>
</span><span>session</span><span>$</span><span>sendCustomMessage</span><span>(</span><span>&quot;timevis:setWindow&quot;</span><span>,</span><span> </span><span>message</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<h4>JavaScript code</h4>
<p>Now we move on to the JavaScript code. First we need to have a way to access the widget JavaScript object from anywhere arbitrary in the JavaScript, so that we can refer to it after its creation. Recall that earlier we defined a <code>timeline</code> variable as the widget:</p>
<div>
<pre><code><span>var</span> <span>timeline</span> <span>=</span> <span>new</span> <span>vis</span><span>.</span><span>Timeline</span><span>(</span><span>document</span><span>.</span><span>getElementById</span><span>(</span><span>el</span><span>.</span><span>id</span><span>),</span> <span>[],</span> <span>{});</span>
</code></pre>
</div>
<p>This <code>timeline</code> object is the actual widget, and is the object we call the API methods (such as <code>setWindow()</code>) on. Therefore, we need to have a way to access this widget from anywhere arbitrarily in the JavaScript code. In order to make it easily available, we can attach it to the HTML element housing the widget by placing the following line inside <code>renderValue()</code>:</p>
<div>
<pre><code><span>document</span><span>.</span><span>getElementById</span><span>(</span><span>elementId</span><span>).</span><span>timeline</span> <span>=</span> <span>timeline</span><span>;</span>
</code></pre>
</div>
<p>Since that attachment only needs to happen once per widget, you can place it inside the initialization code (as described <a target="_blank" href="http://deanattali.com/blog/htmlwidgets-tips/#init-once">above</a>). What this line of code achieves is that now we can access the timeline widget associated with a specific HTML ID using <code>document.getElementById(id).timeline</code>.</p>
<p>Now that we have an R function that sends a JavaScript message with the arguments, and we have a reference to the timeline widget, all that is left to do is implement the JavaScript function that listens for the message coming from Shiny and make the API call:</p>
<div>
<pre><code><span>if</span> <span>(</span><span>HTMLWidgets</span><span>.</span><span>shinyMode</span><span>)</span> <span>{</span>
  <span>Shiny</span><span>.</span><span>addCustomMessageHandler</span><span>(</span><span>&quot;timevis:setWindow&quot;</span><span>,</span> <span>function</span><span>(</span><span>message</span><span>)</span> <span>{</span>
    <span>var</span> <span>el</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>message</span><span>.</span><span>id</span><span>);</span>
    <span>if</span> <span>(</span><span>el</span><span>)</span> <span>{</span>
      <span>el</span><span>.</span><span>timeline</span><span>.</span><span>setWindow</span><span>(</span><span>message</span><span>.</span><span>start</span><span>,</span> <span>message</span><span>.</span><span>end</span><span>,</span> <span>message</span><span>.</span><span>options</span><span>);</span>
    <span>}</span>
  <span>});</span>
<span>}</span>
</code></pre>
</div>
<p>Now you have a working basic implementation of an API function. You can call <code>setWindow()</code> in Shiny, and it will find the appropriate htmlwidget and call its <code>setWindow()</code> method.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip7b-javascript-to-r-handler...tip8a-api-basic#diff">https://github.com/daattali/timevisBasic/compare/tip7b-javascript-to-r-handler…tip8a-api-basic#diff</a></p>
<h3>Tip 8b: Abstracting the code to make it easier to add new API functions</h3>
<p>The code above works just fine, but if you want to start adding support for more API methods, there is going to be a lot of code duplication. So let’s see how we can generalize this code so that we have minimal work to do when we want to add new API functions.</p>
<h4>R code</h4>
<p>On the R side, we can rewrite the <code>setWindow</code> function as follows to be more generic:</p>
<div>
<pre><code><span>setWindow</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>start</span><span>,</span><span> </span><span>end</span><span>,</span><span> </span><span>options</span><span>)</span><span> </span><span>{</span><span>
</span><span># Define the API method name (specific to this function)
</span><span> </span><span>method</span><span> </span><span>&lt;-</span><span> </span><span>&quot;setWindow&quot;</span><span>
</span><span># Get the parameters and pass all the info to JavaScript (non-specific code)
</span><span> </span><span>message</span><span> </span><span>&lt;-</span><span> </span><span>Filter</span><span>(</span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>!</span><span>is.symbol</span><span>(</span><span>x</span><span>),</span><span> </span><span>as.list</span><span>(</span><span>environment</span><span>()))</span><span>
</span><span>session</span><span> </span><span>&lt;-</span><span> </span><span>shiny</span><span>::</span><span>getDefaultReactiveDomain</span><span>()</span><span>
</span><span>method</span><span> </span><span>&lt;-</span><span> </span><span>paste0</span><span>(</span><span>&quot;timevis:&quot;</span><span>,</span><span> </span><span>message</span><span>$</span><span>method</span><span>)</span><span>
</span><span>session</span><span>$</span><span>sendCustomMessage</span><span>(</span><span>method</span><span>,</span><span> </span><span>message</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>You can compare this version to the previous version of the function, and hopefully you’ll see that the result is identical. The one line there that might be confusing is the one with <code>Filter()</code>; basically, it looks at all the objects in the current environment and adds them all to a list, but it filters out any argument that was not given a value. As you can see, only the first line of code <code>method &lt;- &quot;setWindow&quot;</code> is specific to this function, while the rest of the code is completely generalized. This means we can now pull out all this code into a separate function, let’s call it <code>callJS()</code>:</p>
<div>
<pre><code><span>callJS</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>()</span><span> </span><span>{</span><span>
</span><span>message</span><span> </span><span>&lt;-</span><span> </span><span>Filter</span><span>(</span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>!</span><span>is.symbol</span><span>(</span><span>x</span><span>),</span><span> </span><span>as.list</span><span>(</span><span>parent.frame</span><span>(</span><span>1</span><span>)))</span><span>
</span><span>session</span><span> </span><span>&lt;-</span><span> </span><span>shiny</span><span>::</span><span>getDefaultReactiveDomain</span><span>()</span><span>
</span><span>method</span><span> </span><span>&lt;-</span><span> </span><span>paste0</span><span>(</span><span>&quot;timevis:&quot;</span><span>,</span><span> </span><span>message</span><span>$</span><span>method</span><span>)</span><span>
</span><span>session</span><span>$</span><span>sendCustomMessage</span><span>(</span><span>method</span><span>,</span><span> </span><span>message</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>And now our API function simply becomes</p>
<div>
<pre><code><span>setWindow</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>start</span><span>,</span><span> </span><span>end</span><span>,</span><span> </span><span>options</span><span>)</span><span> </span><span>{</span><span>
</span><span>method</span><span> </span><span>&lt;-</span><span> </span><span>&quot;setWindow&quot;</span><span>
</span><span>callJS</span><span>()</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>Now we have a very simple way to add new API functions since most of the heavy lifting is done by <code>callJS()</code>. For example, if we wanted to add support for the <code>addCustomTime()</code> method of the JavaScript library, the R code would only need the following simple function added:</p>
<div>
<pre><code><span>addCustomTime</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>id</span><span>,</span><span> </span><span>time</span><span>,</span><span> </span><span>itemId</span><span>)</span><span> </span><span>{</span><span>
</span><span>method</span><span> </span><span>&lt;-</span><span> </span><span>&quot;addCustomTime&quot;</span><span>
</span><span>callJS</span><span>()</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<h4>JavaScript code</h4>
<p>So we have a nice generic system for adding API functions on the R side, but we should also try to abstract the process as much as possible on the JavaScript side.</p>
<p>The idea here is that instead of manually defining all the message handlers, we can have some generic code that takes care of defining all the message handlers. Each message handler should call an appropriate method on the htmlwidget that will know what to do for its message type (message type = API method). This will solve another problem as well: remember that in the basic implementation we attached the <code>timeline</code> widget to the HTML element of the htmlwidget? It can be considered bad programming practice to expose the widget directly because then anyone can manipulate it freely. Instead, it’s safer to only expose a pre-defined set of functions that we want to allow the user to call.</p>
<p>So what we’ll do is instead of making the raw <code>timeline</code> object available through the HTML element, we’ll only make a reference to the htmlwidget available, and we’ll add API functions to the htmlwidget.</p>
<p>To add a reference to the widget from the HTML element, add the following line of code to the initialization code inside <code>renderValue()</code>:</p>
<div>
<pre><code><span>document</span><span>.</span><span>getElementById</span><span>(</span><span>elementId</span><span>).</span><span>widget</span> <span>=</span> <span>this</span><span>;</span>
</code></pre>
</div>
<p>Next we add the API function (<code>setWindow()</code> and <code>addCustomTime()</code> in this case) to the return value of the htmlwidget:</p>
<div>
<pre><code><span>factory</span> <span>:</span> <span>function</span><span>(</span><span>el</span><span>,</span> <span>width</span><span>,</span> <span>height</span><span>)</span> <span>{</span>
  <span>return</span> <span>{</span>
    <span>renderValue</span><span>:</span> <span>function</span><span>(</span><span>opts</span><span>)</span> <span>{</span>
      <span>...</span>
    <span>},</span>
    <span>setWindow</span> <span>:</span> <span>function</span><span>(</span><span>params</span><span>)</span> <span>{</span>
      <span>timeline</span><span>.</span><span>setWindow</span><span>(</span><span>params</span><span>.</span><span>start</span><span>,</span> <span>params</span><span>.</span><span>end</span><span>,</span> <span>params</span><span>.</span><span>options</span><span>);</span>
    <span>},</span>   
    <span>addCustomTime</span> <span>:</span> <span>function</span><span>(</span><span>params</span><span>)</span> <span>{</span>
      <span>timeline</span><span>.</span><span>addCustomTime</span><span>(</span><span>params</span><span>.</span><span>time</span><span>,</span> <span>params</span><span>.</span><span>itemId</span><span>);</span>
    <span>}</span>
  <span>}</span>
<span>}</span>
</code></pre>
</div>
<p>And lastly we generalize the code to add message handlers:</p>
<div>
<pre><code><span>if</span> <span>(</span><span>HTMLWidgets</span><span>.</span><span>shinyMode</span><span>)</span> <span>{</span>
  <span>var</span> <span>fxns</span> <span>=</span> <span>[</span><span>'setWindow'</span><span>,</span> <span>'addCustomTime'</span><span>];</span>

  <span>var</span> <span>addShinyHandler</span> <span>=</span> <span>function</span><span>(</span><span>fxn</span><span>)</span> <span>{</span>
    <span>return</span> <span>function</span><span>()</span> <span>{</span>
      <span>Shiny</span><span>.</span><span>addCustomMessageHandler</span><span>(</span>
        <span>&quot;timevis:&quot;</span> <span>+</span> <span>fxn</span><span>,</span> <span>function</span><span>(</span><span>message</span><span>)</span> <span>{</span>
          <span>var</span> <span>el</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>message</span><span>.</span><span>id</span><span>);</span>
          <span>if</span> <span>(</span><span>el</span><span>)</span> <span>{</span>
            <span>el</span><span>.</span><span>widget</span><span>[</span><span>fxn</span><span>](</span><span>message</span><span>);</span>
          <span>}</span>
        <span>}</span>
      <span>);</span>
    <span>}</span>
  <span>};</span>

  <span>for</span> <span>(</span><span>var</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span>&lt;</span> <span>fxns</span><span>.</span><span>length</span><span>;</span> <span>i</span><span>++</span><span>)</span> <span>{</span>
    <span>addShinyHandler</span><span>(</span><span>fxns</span><span>[</span><span>i</span><span>])();</span>
  <span>}</span>
<span>}</span>
</code></pre>
</div>
<p>Whenever we want to add a new API function, we now just add the function to the htmlwidget return value, and add its name in the <code>fxns</code> variable in the above code chunk.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip8a-api-basic...tip8b-api-abstract#diff">https://github.com/daattali/timevisBasic/compare/tip8a-api-basic…tip8b-api-abstract#diff</a></p>
<h3>Tip 8c: Support chaining API functions with pipes (<code>%>%</code>)</h3>
<p>Now that we made it easy to add many API functions, we also wan to make it easy to <em>call</em> multiple API functions together, one after the other. The natural way many people will want to do that is by chaining functions together using the magrittr <code>%>%</code> pipe. For example, instead of running</p>
<div>
<pre><code><span>addCustomTime</span><span>(</span><span>&quot;timeline&quot;</span><span>,</span><span> </span><span>time</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>)</span><span>
</span><span>setWindow</span><span>(</span><span>&quot;timeline&quot;</span><span>,</span><span> </span><span>start</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>()</span><span> </span><span>-</span><span> </span><span>1</span><span>,</span><span> </span><span>end</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>()</span><span> </span><span>+</span><span> </span><span>1</span><span>)</span><span>
</span></code></pre>
</div>
<p>It can be easier to type</p>
<div>
<pre><code><span>&quot;timeline&quot;</span><span> </span><span>%>%</span><span>
</span><span>addCustomTime</span><span>(</span><span>time</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>())</span><span> </span><span>%>%</span><span>
</span><span>setWindow</span><span>(</span><span>start</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>()</span><span> </span><span>-</span><span> </span><span>1</span><span>,</span><span> </span><span>end</span><span> </span><span>=</span><span> </span><span>Sys.Date</span><span>()</span><span> </span><span>+</span><span> </span><span>1</span><span>)</span><span>
</span></code></pre>
</div>
<p>Right now, the first version will work, but the second version will not. To support it is actually pretty easy though, all we have to do is make sure each API function accepts the ID as its first argument (we’re already doing that), and make sure the API functions also <em>return</em> that same ID as their value.</p>
<h4>R code</h4>
<p>Simply add the following return call at the end of the <code>callJS()</code> function:</p>
<div>
<pre><code><span>return</span><span>(</span><span>message</span><span>$</span><span>id</span><span>)</span><span>
</span></code></pre>
</div>
<p>And that’s it! No JavaScript changes. Now you can chain your API functions (assuming, of course, that you have the magrittr pipe loaded).</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip8b-api-abstract...tip8c-api-chain#diff">https://github.com/daattali/timevisBasic/compare/tip8b-api-abstract…tip8c-api-chain#diff</a></p>
<h3>Tip 8d: Make API functions work outside of Shiny too</h3>
<p>Right now, calling API functions is only possible within Shiny apps, using the widget’s ID after the widget has been created. It would be great if we could call an API function on the widget during initialization, such as <code>addCustomTime(timevis(), time = Sys.Date)</code>. There are two benefits to this syntax: first of all, it would allow us to call API functions on the widget immediately during initialization. Secondly, it would allow us to use API functions on the widget even when we’re not using Shiny (for example, in an R-markdown document or in the R console).</p>
<p>The problem is that we can’t simply try to call the API function on an htmlwidget before it’s created, because the function would simply not return anything since the widget takes time to initialize. We need to somehow delay the API functions to only run after the widget initializes. And here’s how we can do that: when an API function gets called on an htmlwidget, instead of trying to run it immediately, we can simply save it as a property of the widget. Then when the widget gets created, it can look at what API functions were called on it and are in queue, and run them one by one. Simple!</p>
<h4>R code</h4>
<p>We need to have some sort of list attached to the htmlwidget that will keep track of all API requests. In the <code>timevis()</code> function, where we bundle together all the data and send it to JavaScript, add the following simple line:</p>
<div>
<pre><code><span>x</span><span>$</span><span>api</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>()</span><span>
</span></code></pre>
</div>
<p>Now we have a place to store any future API function requests. Remember that the goal is to be able to call an API function directly using an htmlwidget, rather than using an ID. So the next thing we need to do is allow the API functions to be called with an htmlwidget as the first parameter instead of an ID (which is what is currently expected). Recall that all API function calls go through the <code>callJS()</code> function, so add the following few lines to that function, after the <code>session</code> variable gets defined:</p>
<div>
<pre><code><span>if</span><span> </span><span>(</span><span>methods</span><span>::</span><span>is</span><span>(</span><span>message</span><span>$</span><span>id</span><span>,</span><span> </span><span>&quot;timevisBasic&quot;</span><span>))</span><span> </span><span>{</span><span>
</span><span>widget</span><span> </span><span>&lt;-</span><span> </span><span>message</span><span>$</span><span>id</span><span>
</span><span>message</span><span>$</span><span>id</span><span> </span><span>&lt;-</span><span> </span><span>NULL</span><span>
</span><span>widget</span><span>$</span><span>x</span><span>$</span><span>api</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>widget</span><span>$</span><span>x</span><span>$</span><span>api</span><span>,</span><span> </span><span>list</span><span>(</span><span>message</span><span>))</span><span>
</span><span>return</span><span>(</span><span>widget</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>Hopefully you can understand what that code does: it looks to see if the first parameter (<code>id</code>) is actually an object of type <code>timevisBasic</code>, which indicates it’s an htmlwidget. If it is, then instead of calling JavaScript immediately, simply save all the request info (the API function’s name and the arguments) into the special list we defined earlier. Notice that we also return the widget, which is important if we want to be able to chain API calls (eg. <code>timeline() %>% setWindow(...) %>% addCustomTime(...)</code> vs <code>addCustomTime(setWindow(timeline(), ...))</code>).</p>
<p>The one thing I don’t love about this solution is that we’re overloading the <code>id</code> parameter so that it actually accepts two very different types of inputs. In an ideal world this would not happen, but in practice this allows us the great flexibility of calling an API function in any way we want.</p>
<h4>JavaScript code</h4>
<p>The last piece of the puzzle is actually calling the API functions once the widget gets created. If we go back to the <code>renderValue()</code> function, that’s where we get all the information from R about what the widget should contain, and that’s where we initialize the widget. So all we need to do is check if there are any outstanding API function calls, loop through them, and call them one by one. This can actually be done in a very simple way, just add the following code to the end of the <code>renderValue()</code> function:</p>
<div>
<pre><code><span>// Now that the timeline is initialized, call any outstanding API</span>
<span>// functions that the user wantd to run on the timeline before it was</span>
<span>// ready</span>
<span>var</span> <span>numApiCalls</span> <span>=</span> <span>opts</span><span>[</span><span>'api'</span><span>].</span><span>length</span><span>;</span>
<span>for</span> <span>(</span><span>var</span> <span>i</span> <span>=</span> <span>0</span><span>;</span> <span>i</span> <span>&lt;</span> <span>numApiCalls</span><span>;</span> <span>i</span><span>++</span><span>)</span> <span>{</span>
  <span>var</span> <span>call</span> <span>=</span> <span>opts</span><span>[</span><span>'api'</span><span>][</span><span>i</span><span>];</span>
  <span>var</span> <span>method</span> <span>=</span> <span>call</span><span>.</span><span>method</span><span>;</span>
  <span>try</span> <span>{</span>
    <span>this</span><span>[</span><span>method</span><span>](</span><span>call</span><span>);</span>
  <span>}</span> <span>catch</span><span>(</span><span>err</span><span>)</span> <span>{}</span>
<span>}</span>
</code></pre>
</div>
<p>Now you can call API functions using an ID or an htmlwidget object, and you can even chain calls easily. I think this solution is failry simple and elegant, and can easily be implemented in other htmlwidget packages.</p>
<p>See the implementation of this tip in <code>timevisBasic</code>:<br>
<a target="_blank" href="https://github.com/daattali/timevisBasic/compare/tip8c-api-chain...tip8d-api-not-just-shiny#diff">https://github.com/daattali/timevisBasic/compare/tip8c-api-chain…tip8d-api-not-just-shiny#diff</a></p>
<hr>
<p>That’s all the advice I can give based on what I learned making my first htmlwidget. Hopefully now if you look at <a target="_blank" href="https://github.com/daattali/timevis/blob/v0.2/inst/htmlwidgets/timevis.js">the JavaScript code</a> for the <code>timevis</code> widget, you’ll understand everything that I did there.</p>
<p>As always, feel free to <a target="_blank" href="http://deanattali.com/contact">contact me</a>. Any comments and feedback are appreciated, especially if any of my code or ideas seem strange.</p>
<p><span></span><em>*It was actually a couple months ago. I started writing this tutorial one week after releasing <code>timevis</code> but only wrote the accompanying <code>timevisBasic</code> package and the rest of the article several weeks later.</em></p>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="https://www.r-bloggers.com/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/"></div></div><div><a data-url="https://www.r-bloggers.com/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/" data-counturl="https://www.r-bloggers.com/how-to-write-a-useful-htmlwidgets-in-r-tips-and-walk-through-a-real-example/" data-count="vertical" data-text="How to write a useful htmlwidgets in R: tips and walk-through a real example" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://deanattali.com/blog/htmlwidgets-tips/"> Dean Attali's 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/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/?s=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/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/VVLavHLZJE4"></a></div>