<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Hrishi Mittal's Blog]]></title><description><![CDATA[Hrishi Mittal's Blog]]></description><link>https://hrishimittal.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 11:37:36 GMT</lastBuildDate><atom:link href="https://hrishimittal.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to build an image gallery in Rails with Stimulus]]></title><description><![CDATA[Click here to watch a video version of this tutorial.
This lesson is from Full Stack Rails Mastery
In this lesson, we’ll create an interactive image gallery for the product page using Stimulus.  
Here we have all the thumbnails of the product’s image...]]></description><link>https://hrishimittal.hashnode.dev/how-to-build-an-image-gallery-in-rails-with-stimulus</link><guid isPermaLink="true">https://hrishimittal.hashnode.dev/how-to-build-an-image-gallery-in-rails-with-stimulus</guid><category><![CDATA[Rails]]></category><category><![CDATA[Rails 7.1]]></category><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[hotwire]]></category><category><![CDATA[stimulus]]></category><category><![CDATA[rubyonrails]]></category><dc:creator><![CDATA[Hrishi Mittal]]></dc:creator><pubDate>Thu, 25 Jul 2024 09:47:55 GMT</pubDate><content:encoded><![CDATA[<p><a target="_blank" href="https://learnetto.com/tutorials/how-to-build-an-image-gallery-in-rails-with-stimulus?utm_source=hashnode&amp;utm_campaign=stimulusgallery"><img src="https://miro.medium.com/v2/resize:fit:1400/1*_21389URG6MZpGCp0UXE_w.png" alt="How to build an image gallery with Stimulus in Rails" /></a></p>
<p><a target="_blank" href="https://learnetto.com/tutorials/how-to-build-an-image-gallery-in-rails-with-stimulus?utm_source=hashnode&amp;utm_campaign=stimulusgallery">Click here to watch a video version of this tutorial</a><a target="_blank" href="https://learnetto.com/tutorials/how-to-build-an-image-gallery-in-rails-with-stimulus?utm_source=hashnode&amp;utm_campaign=stimulusgallery">.</a></p>
<p><strong>This lesson is from</strong> <a target="_blank" href="https://learnetto.com/users/hrishio/courses/full-stack-rails-mastery?utm_source=hashnode&amp;utm_campaign=stimulusgallery"><strong>Full Stack Rails Mastery</strong></a></p>
<p>In this lesson, we’ll create an interactive image gallery for the product page using Stimulus.  </p>
<p>Here we have all the thumbnails of the product’s images and the first one is displayed as a large image.</p>
<p><img src="https://d3op8yelmiam9s.cloudfront.net/public/images/2024-07-23/1721725537160-Screenshot%202024-07-23%20at%2010.05.32.png" alt /></p>
<p>We want to be able to click on any thumbnail to see the large version of it above.</p>
<p>Stimulus is a part of Hotwire. It’s "<em>a modest JavaScript framework for the HTML you already have</em>".  </p>
<p><img src="https://d3op8yelmiam9s.cloudfront.net/public/images/2024-07-23/1721725789380-stimulus.png" alt /></p>
<p>Stimulus gives you a lightweight way to add interactivity to webpages.</p>
<p>You start by adding 3 data attributes to your HTML:</p>
<ol>
<li><p>controller</p>
</li>
<li><p>target</p>
</li>
<li><p>action</p>
</li>
</ol>
<p><strong>Stimulus automatically connects DOM elements to JavaScript objects called controllers</strong>.</p>
<p>The controller is where you define the logic of the interaction.</p>
<p>In the example on the Stimulus homepage, there's a form with an input text field where you can enter a name. When you click greet, it displays the text “Hello” with the entered name.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">data-controller</span>=<span class="hljs-string">"hello"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">data-hello-target</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-action</span>=<span class="hljs-string">"click-&gt;hello#greet"</span>&gt;</span>
    Greet
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">data-hello-target</span>=<span class="hljs-string">"output"</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>So the first data attribute is <strong>controller</strong> with the value "<em>hello</em>".  </p>
<p>You set that on the outer div which contains the rest of the UI elements.  </p>
<p>There are two <strong>targets</strong> - one for input called <em>name</em> and another for the <em>output</em>.  </p>
<p>And there's an <strong>action</strong> attribute set on the button with the value "<em>click-&gt;hello#greet</em>".  </p>
<p>This means when the button is clicked, call the greet method in the hello controller.  </p>
<p>Now, let’s look at the controller code.  </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// hello_controller.js</span>
<span class="hljs-keyword">import</span> { Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">"stimulus"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span> </span>{
  <span class="hljs-keyword">static</span> targets = [ <span class="hljs-string">"name"</span>, <span class="hljs-string">"output"</span> ]

  greet() {
    <span class="hljs-built_in">this</span>.outputTarget.textContent =
      <span class="hljs-string">`Hello, <span class="hljs-subst">${<span class="hljs-built_in">this</span>.nameTarget.value}</span>!`</span>
  }
}
</code></pre>
<p>We start by importing the built-in <strong>Controller</strong> class from Stimulus. We will extend this to define our own hello controller.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">"stimulus"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span> </span>{
</code></pre>
<p>Note the naming convention here. The file is called <strong>hello_controller.js</strong>. That’s the controller name followed by "_controller.js". The name hello is what's used as the identifier value for the <strong>data-controller</strong> attribute on the container div.  </p>
<p>Next we define a list of targets as static properties on the class.</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">static</span> targets = [ <span class="hljs-string">"name"</span>, <span class="hljs-string">"output"</span> ]
</code></pre>
<p><strong>Targets map HTML elements to controller properties.</strong></p>
<p>We have two targets here - the input name and the output.  </p>
<p>Stimulus will automatically create corresponding properties for each of them - <strong>this.nameTarget</strong> and <strong>this.outputTarget</strong> respectively.  </p>
<p>Again, note the naming convention here. this dot the name of the target followed by the word Target with a capital T.  </p>
<p>Finally, we have the greet method definition</p>
<pre><code class="lang-javascript">  greet() {
    <span class="hljs-built_in">this</span>.outputTarget.textContent =
      <span class="hljs-string">`Hello, <span class="hljs-subst">${<span class="hljs-built_in">this</span>.nameTarget.value}</span>!`</span>
  }
</code></pre>
<p>The backticks mean it’s a template literal, and the dollar curly brackets <em>${ }</em> are used to embed an expression within the string. This is similar to string interpolation in Ruby with hash curly brackets <em>#{ }</em>.  </p>
<p>Now that we have the basic idea of how Stimulus works, let’s put it to use by building our very own first Stimulus controller.  </p>
<p>Instead of coding it from scratch, we can use a Rails generator:</p>
<pre><code class="lang-bash">bin/rails generate stimulus gallery
</code></pre>
<p>And that will create <strong>gallery_controller.js</strong> in app/javascript/controllers.  </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Controller } <span class="hljs-keyword">from</span> <span class="hljs-string">"@hotwired/stimulus"</span>

<span class="hljs-comment">// Connects to data-controller="gallery"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Controller</span> </span>{
  connect() {
  }
}
</code></pre>
<p>First we import the Controller class from stimulus and then extend it.</p>
<p>Stimulus has automatically added a method called <strong>connect</strong>.</p>
<p>This is a special method - <strong>a lifecycle callback</strong>. There are a few of these special methods. connect runs anytime the controller is connected to the DOM.  </p>
<p>To see it in action, let’s add a console log statement that says image gallery controller connected.</p>
<pre><code class="lang-javascript">connect() {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'image gallery controller connected'</span>)
}
</code></pre>
<p>Then we need to define a <strong>data-controller</strong> attribute so Stimulus knows which DOM element to connect this controller to.  </p>
<p>Let’s go to the product partial (<strong>app/views/products/_product.html.erb</strong>) and add a data controller attribute to the outermost div. And set its value to gallery.</p>
<pre><code class="lang-xml">  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"min-h-screen py-12 sm:pt-20"</span> <span class="hljs-attr">data-controller</span>=<span class="hljs-string">"gallery"</span>&gt;</span>
</code></pre>
<p>Now refresh the page in the browser and we see our log message in the console.  </p>
<p><img src="https://d3op8yelmiam9s.cloudfront.net/public/images/2024-07-23/1721727414537-connected.png" alt /></p>
<p>Next, let’s set the data-action attribute on the thumbnails. Because that’s what we want to click. We set the action to a method called “display”.</p>
<pre><code class="lang-ruby">&lt;%= image_tag image, <span class="hljs-class"><span class="hljs-keyword">class</span>: "<span class="hljs-title">thumbnail</span>", <span class="hljs-title">data</span>: {<span class="hljs-title">action</span>: "<span class="hljs-title">click</span>-&gt;<span class="hljs-title">gallery</span><span class="hljs-comment">#display"} %&gt;</span></span>
</code></pre>
<p>Ok, now let’s define this display method in the controller. First, let’s simply console log a message “<em>display clicked image</em>”. So we know our action attribute is working correctly.</p>
<pre><code class="lang-javascript">display() {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'display clicked image'</span>)
}
</code></pre>
<p>Let’s test it in the browser. Refresh and click a thumbnail. And there we have our second console log message.  </p>
<p><img src="https://d3op8yelmiam9s.cloudfront.net/public/images/2024-07-23/1721727448282-display.png" alt /></p>
<p>Ok now, we need one more data attribute - a target.  </p>
<p>That would be the big image at the top of the gallery. So inside that image tag, let's add data “gallery-target” and we’ll call it “display”</p>
<pre><code class="lang-ruby">&lt;%= image_tag product.images.first, <span class="hljs-symbol">id:</span> <span class="hljs-string">"displayed-image"</span>, 
              <span class="hljs-symbol">data:</span> { <span class="hljs-string">"gallery-target"</span>: <span class="hljs-string">"display"</span> } %&gt;
</code></pre>
<p>If we refresh and look at the elements in the console, we can see the data attributes we’ve set.  </p>
<p>Ok, now let’s proceed with defining the rest of the controller.  </p>
<p>First, let’s define our static targets. We only need one here called “display”:</p>
<pre><code class="lang-plaintext">static targets = ["display"]
</code></pre>
<p>And finally, let’s define the logic of the display method. Let’s remove the console log statement.  </p>
<p>We want to set the value of the src attribute of the display target image.  </p>
<p>So we can write:</p>
<pre><code class="lang-javascript">display() {
  <span class="hljs-built_in">this</span>.displayTarget.src = event.currentTarget.src
}
</code></pre>
<p>Remember the naming convention here - target name “display” followed by the word Target with a capital T.</p>
<p>We can get the src of the thumbnail image via “event” i.e. the click event which we used in the data-action attribute. </p>
<p><strong>currentTarget</strong> is the DOM target on which the data-action attribute is defined. In this case, it’ll be whichever thumbnail image is clicked.  </p>
<p>Ok, now let’s try that in the browser. Refresh and click a different thumbnail And there you go - the big displayed image changes to that one. Try clicking another one and it works.  </p>
<p><img src="https://d3op8yelmiam9s.cloudfront.net/public/images/2024-07-23/1721727575486-gallery.gif" alt /></p>
<p>So there you have it - we have created our first Stimulus controller. We were able to create an image gallery with very little code!</p>
<blockquote>
<p><strong><em>If you enjoyed this lesson, you’re going to love</em></strong> <a target="_blank" href="https://learnetto.com/users/hrishio/courses/full-stack-rails-mastery?utm_source=hashnode&amp;utm_campaign=stimulusgallery"><strong><em>Full Stack Rails Mastery</em></strong></a><strong><em>. Try out some more free lessons and get access to a comprehensive Rails course.</em></strong></p>
</blockquote>
<p><a target="_blank" href="https://medium.com/tag/rails?source=post_page-----e92eea0b3080---------------rails-----------------">  
</a></p>
]]></content:encoded></item></channel></rss>