<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>htmlwidgets on R Views</title>
    <link>https://rviews.rstudio.com/categories/htmlwidgets/</link>
    <description>Recent content in htmlwidgets on R Views</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 26 Nov 2019 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://rviews.rstudio.com/categories/htmlwidgets/" rel="self" type="application/rss+xml" />
    
    
    
    
    <item>
      <title>Introducing sortable to add drag-and-drop to your shiny apps</title>
      <link>https://rviews.rstudio.com/2019/11/26/using-sortable-for-drag-and-drop-in-shiny-apps/</link>
      <pubDate>Tue, 26 Nov 2019 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2019/11/26/using-sortable-for-drag-and-drop-in-shiny-apps/</guid>
      <description>
        


&lt;p&gt;&lt;em&gt;Andrie de Vries is the author of “R for Dummies” and a Solutions Engineer at RStudio&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Earlier this year I was a student on the &lt;a href=&#34;RStudio%20Instructor%20Training&#34;&gt;RStudio Instructor Training&lt;/a&gt;, taught by the inspiratational Greg Wilson. I remember several tips from this course, for example that you should always try to draw a &lt;a href=&#34;https://docs.google.com/presentation/d/1k45SqyM-w4DtK7dmedeX7pk_r8B9Aq0FKKCxC04pTRM/&#34;&gt;concept map&lt;/a&gt; of the material you are teaching. And, secondly, that you should make liberal use of &lt;a href=&#34;https://docs.google.com/presentation/d/1PBxBFpkB4w-C3_l2rWdGMtjxaxDeu8gVP0K0CHJfbdQ/&#34;&gt;formative assessment&lt;/a&gt; during your teaching.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-11-26-sortable-part-1_files/concept-map-of-concept-maps.png&#34; /&gt;&lt;!-- --&gt;&lt;/p&gt;
&lt;p&gt;A formative question helps the student grow their understanding of a topic, in contrast to a normative question that attempts to assess the skills of the student. Greg mentioned several archetypal formative questions, including a ranking question. In this type of question, the teacher provides the student with a list of options, and the task is to arrange these items in the correct order. It’s a great formative question, because you’re not testing the student’s memory (you provide all the terms) but you’re testing their understanding and reasoning about the topic.&lt;/p&gt;
&lt;p&gt;This made me wonder what it would take to create ranking type questions in &lt;code&gt;learnr&lt;/code&gt; tutorials. (A &lt;code&gt;learnr&lt;/code&gt; tutorial is a special type of R Markdown document with a &lt;code&gt;shiny&lt;/code&gt; runtime, that allows quizzes and other question types.)&lt;/p&gt;
&lt;p&gt;Now, to be able to rank items in a &lt;code&gt;shiny&lt;/code&gt; app, you first need to enable drag-and-drop behaviour in &lt;code&gt;shiny&lt;/code&gt;. This was not something I had seen at the time (around May 2019), so I went searching…&lt;/p&gt;
&lt;p&gt;Within hours I found a highly experimental (and incomplete) package by Kent Russell, called &lt;code&gt;sortable&lt;/code&gt;. The &lt;code&gt;sortable&lt;/code&gt; package was an &lt;code&gt;htmlwidget&lt;/code&gt; that wrapped the &lt;code&gt;SortableJS&lt;/code&gt; JavaScript library. The &lt;code&gt;SortableJS&lt;/code&gt; &lt;a href=&#34;https://sortablejs.github.io/Sortable/&#34;&gt;library&lt;/a&gt; is a “JavaScript library for reorderable drag-and-drop lists”.&lt;/p&gt;
&lt;p&gt;This sounded exactly what I needed, but there was a snag. Kent started the package during a period where he created a new &lt;code&gt;htmlwidget&lt;/code&gt; every week, and the package itself was functioning, but incomplete. However, the existing functionality was tantalizing - it was possible to reorder all sorts of items in a the &lt;code&gt;shiny&lt;/code&gt; UI, but it was not possible to read the return value. So you could re-order elements, but you could not use this information in a &lt;code&gt;shiny&lt;/code&gt; reactive element. In other words, the &lt;code&gt;shiny&lt;/code&gt; app could not respond to the input.&lt;/p&gt;
&lt;div id=&#34;first-steps-in-updating-the-package&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;First steps in updating the package&lt;/h2&gt;
&lt;p&gt;My first steps in updating the package was to attempt to close the feedback loop. Specifically, I needed the JavaScript object to communicate back to R.&lt;/p&gt;
&lt;p&gt;Fortunately, this is a well-understood problem (at least for the people who wrote &lt;code&gt;htmlwidgets&lt;/code&gt; and &lt;code&gt;shiny&lt;/code&gt;). And I was especially happy that Barret Schloerke was prepared to help me with some pointers.&lt;/p&gt;
&lt;p&gt;In a nutshell, the &lt;code&gt;sortable&lt;/code&gt; package contains a function &lt;code&gt;sortable_js_capture_input()&lt;/code&gt; that does the translation between the &lt;code&gt;htmlwidget&lt;/code&gt; and the &lt;code&gt;shiny&lt;/code&gt; app.&lt;/p&gt;
&lt;p&gt;Most users of &lt;code&gt;sortable&lt;/code&gt; do not need to know this, but the function takes a &lt;code&gt;shiny&lt;/code&gt; input ID as input, runs some JavaScript to modify the &lt;code&gt;shiny&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sortable_js_capture_input &amp;lt;- function(input_id) {
  # can call jquery as shiny will always have jquery
  inner_text &amp;lt;- paste0(
    &amp;quot;$.map(&amp;quot;,
    &amp;quot;  this.el.children, &amp;quot;,
    get_child_id_or_text_js_fn(),
    &amp;quot;)&amp;quot;,
    collapse = &amp;quot;\n&amp;quot;
  )
  js_text &amp;lt;- &amp;quot;function(evt) {
  if (typeof Shiny !== \&amp;quot;undefined\&amp;quot;) {
    Shiny.setInputValue(\&amp;quot;%s:sortablejs.rank_list\&amp;quot;, %s)
  }
}&amp;quot;

  js &amp;lt;- sprintf(js_text, input_id, inner_text)

  htmlwidgets::JS(js)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;magic-can-happen-with-sortable&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Magic can happen with sortable&lt;/h2&gt;
&lt;p&gt;Once it was possible to capture the input from &lt;code&gt;SortableJS&lt;/code&gt; and pass this value to the shiny input object, it was possible to create some magic.&lt;/p&gt;
&lt;p&gt;For example, in the original version of the package, Kent Russell wrote a simplified version of a shiny app that let’s the user drag-and-drop the columns of a data frame into separate lists.&lt;/p&gt;
&lt;p&gt;Once the shiny app knows what the values of these input lists are, it is quite simple to draw a plot based on these inputs:&lt;/p&gt;
&lt;video height=&#34;400px&#34;controls&gt;
&lt;source src=&#34;https://s3.amazonaws.com/rviews.rstudio.com/2019-11-26-sortable/sortable-magic.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;You can try the app at &lt;a href=&#34;https://andrie-de-vries.shinyapps.io/sortable_drag_vars_to_plot_app/&#34; class=&#34;uri&#34;&gt;https://andrie-de-vries.shinyapps.io/sortable_drag_vars_to_plot_app/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;using-the-package&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Using the package&lt;/h2&gt;
&lt;p&gt;The package is not yet available from CRAN, but you can find the development version at &lt;a href=&#34;https://github.com/rstudio/sortable&#34; class=&#34;uri&#34;&gt;https://github.com/rstudio/sortable&lt;/a&gt;, and the &lt;code&gt;pkgdown&lt;/code&gt; documentation at &lt;a href=&#34;https://rstudio.github.io/sortable/&#34; class=&#34;uri&#34;&gt;https://rstudio.github.io/sortable/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To install the development version, use:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# install.packages(&amp;quot;remotes&amp;quot;)
remotes::install_github(&amp;quot;rstudio/sortable&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then you can try any of the examples in the documentation. For example, to run the &lt;code&gt;shiny&lt;/code&gt; app with drag-and-drop plots, try:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shiny::runApp(system.file(&amp;quot;shiny-examples/drag_vars_to_plot&amp;quot;, package = &amp;quot;sortable&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;what-happened-next&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;What happened next&lt;/h2&gt;
&lt;p&gt;I was excited about the potential of the package, so I contacted Kent Russell. In turn, he was delighted that somebody took his idea and built on it, so we agreed that I will maintain the package, with the substantial help of Barret Schloerke.&lt;/p&gt;
&lt;p&gt;At the start of this post I said my initial inspiration was to find a way to create ranking questions in &lt;code&gt;learnr&lt;/code&gt; tutorials.&lt;/p&gt;
&lt;p&gt;But that’s actually another long story, and I will tell the story of custom question types and &lt;code&gt;question_rank()&lt;/code&gt; in a follow-on to this post in the near future.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2019/11/26/using-sortable-for-drag-and-drop-in-shiny-apps/&#39;;&lt;/script&gt;
      </description>
    </item>
    
  </channel>
</rss>
