[help] Slides example

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

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>

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.textContent = "🙈"

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!


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?

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>
class extends Controller {
  // ...

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