Search code examples
javascriptruby-on-railsrubystimulusjs

Issues regarding Stimulus JS , trying to add buttons which hide/show content on the active page when clicked on


I'm making my first personal project on Ruby on Rails (as well as my first post on Stack Overflow !).

I would like to implement a "productivity" page with dedicated keyboard shortcuts for Mac & Ubuntu users. Cf : Project image

The goal would be to click on the Mac / Linux buttons and display a shortcut version for each OS. I've used Stimulus JS to add a data controller/target/action on the button, when clicked it add / remove a class active or disable which hides the inactive card.

My issue is that the buttons of the second, third, etc. "article" are always linked to the first on. So when clicked on, it still changes the display of the first article instead of the second one.

I don't know if there is a way to compartmentalize each button with its related article with Stimulus ?

My code looks like this :

View :

 <div class="article-cards" ">
      <% @productivity.article.each do |article| %>
        <div class="article-card">
          <div class="article-content">
            <h3><%= article.title%></h3>
            <p><%= article.description%></p>
            <% if article.category == "code" %>
            <div class="article-code">
              <div class="article-code-buttons">
                <button class="btn-article" data-action="click->os-buttons#showLinux">Linux</button>
                <button class="btn-article" data-action="click->os-buttons#showMac">Mac</button>
              </div>
              <div class="article-code-content">
                <div class="article-code-content-linux activate" data-os-buttons-target="linux">
                  <p>Test Linux</p>
                </div>
                <div class="article-code-content-mac disable"  data-os-buttons-target="mac">
                  <p>Test Mac</p>
                </div>
              </div>
            </div>
            <% end %>
          </div>
        </div>
      <% end %>
    </div>

JS Controller :

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="os-buttons"
export default class extends Controller {
  static targets = ["linux", "mac"]

  connect() {

  }

  showMac() {
    this.linuxTarget.classList.remove("active")
    this.linuxTarget.classList.add("disable")
    this.macTarget.classList.remove("disable")
    this.macTarget.classList.add("active")
  }

  showLinux() {
    this.macTarget.classList.remove("active")
    this.macTarget.classList.add("disable")
    this.linuxTarget.classList.remove("disable")
    this.linuxTarget.classList.add("active")
  }
}

Solution

  • Where is your data-controller-os-buttons tag? You seem to have multiple targets with same target name, so a click on a button will will probably only change the first target. Put the controller on each set of buttons.

    <div class="article-code" data-controller="os-buttons">
    

    That should only take action on the set of buttons

    If your controller is before the code you displayed, you have multiple targets (array) and need to figure out which target was clicked by index. Doable, but the multiple controllers should work.