[help] Slides example


#1

I read the book. But have one question. Would it be possible to programmatically add a new slide?


#2

Yes! Where Stimulus differs from other frameworks is that it doesn’t prescribe a particular way to do it. Any way you choose to modify the document is fine. (We refer to Stimulus as “render-agnostic.”)


<div data-controller="slideshow">
  <button data-action="slideshow#previous">←</button>
  <button data-action="slideshow#next">→</button>

  <div data-target="slideshow.slide" class="slide">🐵</div>
</div>

There are two straightforward ways to add a slide. The easiest is to insert a string of HTML:

class extends Controller {
  // ...

  addSlide() {
    this.element.insertAdjacentHTML("beforeend", `
      <div data-target="slideshow.slide" class="slide">🙈</div>
    `)
  }
}

Where you get that HTML is the interesting question. At Basecamp, we often issue Ajax requests to load new HTML from the server. We also receive HTML messages over a WebSocket connection.

Another way is to create and append the element manually:

  addSlide() {
    const element = document.createElement("div")
    element.setAttribute("data-target", "slideshow.slide")
    element.classList.add("slide")
    element.textContent = "🙈"
    this.element.appendChild(element)
  }

You can also use a client-side templating library to do this.

Note that none of this has to be done inside a controller, either. You might very well have another component in your app that adds the slide somehow.

I hope this helps!


#3

I see. So coupling this with a templating library like handlebars can make a powerful combination.

Last question.

If you had a list of buttons, each time one was clicked it would be removed. How would you know the index of the button you just clicked in order to remove it?


#4

No need to keep track of indexes. Stimulus invokes action methods with an event argument, so event.target is a reference to the element which triggered the action.

<ul data-controller="list">
  <li>...<a data-action="list#remove">Remove</a></li>
  <li>...<a data-action="list#remove">Remove</a></li>
  <li>...<a data-action="list#remove">Remove</a></li>
</ul>
class extends Controller {
  // ...

  remove(event) {
    const element = event.target.closest("li")
    if (element) element.remove()
  }
}