<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vlad Andreev</title>
    <description>The latest articles on DEV Community by Vlad Andreev (@vladyio).</description>
    <link>https://dev.to/vladyio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F111475%2F1e9799c3-0cb8-47fe-b86d-e5af04fe23b6.jpeg</url>
      <title>DEV Community: Vlad Andreev</title>
      <link>https://dev.to/vladyio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vladyio"/>
    <language>en</language>
    <item>
      <title>Multi-column drag and drop with SortableJS and Stimulus</title>
      <dc:creator>Vlad Andreev</dc:creator>
      <pubDate>Sun, 18 Feb 2024 05:35:24 +0000</pubDate>
      <link>https://dev.to/vladyio/multi-column-drag-and-drop-with-sortablejs-and-stimulus-3h6a</link>
      <guid>https://dev.to/vladyio/multi-column-drag-and-drop-with-sortablejs-and-stimulus-3h6a</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Recently, in a Rails project, I was tasked with implementing the ability to drag and drop cards both within a single list and between two lists (or columns, for that matter). &lt;/p&gt;

&lt;p&gt;Without further ado, our choice was to use Stimulus. &lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Approach
&lt;/h2&gt;

&lt;p&gt;At first, I tried to implement drag and drop by reinventing the wheel, using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API#drag_events"&gt;Drag and Drop API&lt;/a&gt; directly for event handling. That is, I needed to write an action for all the events like "dragstart", "dragenter" and so on and so forth.&lt;/p&gt;

&lt;p&gt;Quite quickly, it became clear that I was doing absolutely useless job and only complicated code support: describing every step of the drag-and-drop process was quite a pain. There was code that was not very easy to understand at first (especially the calculation of where to throw the cards, and not only that).&lt;/p&gt;

&lt;h2&gt;
  
  
  Stimulus Sortable Component
&lt;/h2&gt;

&lt;p&gt;Well, the obvious thought was to look for something Stimulus-related and ready to use, and there was a solution: &lt;a href="https://www.stimulus-components.com/docs/stimulus-sortable"&gt;Stimulus Sortable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, it worked. But only for one case: dragging stuff within only one column. You see, stimulus-sortable uses &lt;a href="https://github.com/SortableJS/Sortable"&gt;SortableJS&lt;/a&gt; under the hood, which is powerful. &lt;/p&gt;

&lt;p&gt;But it turned out, that the Stimulus component only handled the &lt;code&gt;onUpdate&lt;/code&gt; event and wrapped only a few options out of many available in the original SortableJS. That was not enough for multi-column drag and drop support.&lt;/p&gt;

&lt;p&gt;Well, it's open source, then why not enhance it? And I did locally, it was not that hard: pulled the &lt;a href="https://github.com/stimulus-components/stimulus-sortable"&gt;stimulus-sortable repository&lt;/a&gt;, wrote a couple lines of code (see diff below), ran &lt;code&gt;yarn build&lt;/code&gt; and provided the path to my local package in my original project. It was good to go and it worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// src/index.ts 
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;export default class extends Controller {
&lt;/span&gt;  // ...
&lt;span class="gi"&gt;+ groupValue: string
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;// ...
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;static values = {
&lt;/span&gt;    // ...
&lt;span class="gi"&gt;+   group: String
&lt;/span&gt;// ... 
&lt;span class="p"&gt;get options (): Sortable.Options {
&lt;/span&gt;    return {
      // ...
&lt;span class="gi"&gt;+     onChange: this.defaultOptions.onChange,
+     group: this.groupValue || this.defaultOptions.group || undefined,
&lt;/span&gt;    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All you need to handle multi-column drag in SortableJS is to &lt;a href="https://sortablejs.github.io/Sortable/#shared-lists"&gt;set the same &lt;code&gt;group&lt;/code&gt; option value&lt;/a&gt; for every list/column&lt;/p&gt;

&lt;p&gt;That was a solution, but... I have my own copy of the package now. That comes with a cost of maintaining my own fork, and we didn't want that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait a minute, can't I just ...
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;...use SortableJS directly in my regular Stimulus controller without having an odd dependency&lt;/em&gt;? Well, yes you can, and it's actually easier, than using the Stimulus component wrapper around it.&lt;/p&gt;

&lt;p&gt;Just do the:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add sortablejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in your project and write this in your Stimulus controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hotwired/stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Sortable&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sortablejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sortable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... here goes your logic to send AJAX requests with updated data&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to register your controller in &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DragController&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./drag_controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;drag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DragController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to add &lt;code&gt;data-controller&lt;/code&gt; for your parent container and provide the shared group name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"drag"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"left-column"&lt;/span&gt; &lt;span class="na"&gt;data-drag-group-value=&lt;/span&gt;&lt;span class="s"&gt;"your_group_name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- cards go here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"right-column"&lt;/span&gt; &lt;span class="na"&gt;data-drag-group-value=&lt;/span&gt;&lt;span class="s"&gt;"your_group_name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- and cards go here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, that's it. Actually, there was no need for a wrapper at all. You can now drag and drop the cards within the same list as well as between multiple lists, just handle the &lt;code&gt;onChange&lt;/code&gt; event for stuff like updating position values.&lt;/p&gt;

&lt;p&gt;And if you need more features that are available in SortableJS, you can just implement them the same way&lt;/p&gt;

</description>
      <category>stimulus</category>
      <category>rails</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What do I write about in my blog as a junior developer?</title>
      <dc:creator>Vlad Andreev</dc:creator>
      <pubDate>Mon, 19 Nov 2018 08:50:04 +0000</pubDate>
      <link>https://dev.to/vladyio/what-do-i-write-about-in-my-blog-as-a-junior-developer-2p9a</link>
      <guid>https://dev.to/vladyio/what-do-i-write-about-in-my-blog-as-a-junior-developer-2p9a</guid>
      <description>&lt;p&gt;Many professional developers with rich experience recommend starting a blog to share whatever comes to one's mind. &lt;/p&gt;

&lt;p&gt;Four years ago I started a blog. I was putting out to the world everything I was trying out and learning at that moment. And let’s be honest, it was rubbish that no one was interested in.&lt;/p&gt;

&lt;p&gt;Later I started a new blog from scratch. I published my translations (English to Russian) of some blog posts I found interesting. One out of five existing posts got attention, and even at this moment, it’s relatively popular (it gets around 30 unique views per week). But I still understand that this content isn’t unique itself and it’s not highly demanded.&lt;/p&gt;

&lt;p&gt;So, guys, do you have any good advice on what to write about when you don’t have many things to share? Maybe I shouldn’t share anything at all?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
