Configurable Controllers
by Julian Rubisch
Bad
<!– index.html –>
<a href=“#” data-controller=“toggle” data-action=“click->toggle#toggle”>
Toggle
</a>
<!-- index.html --> <a href="#" data-controller="toggle" data-action="click->toggle#toggle"> Toggle </a>
// toggle_controller.js
import { Controller } from “@hotwired/stimulus”;
export default class extends Controller {
toggle(e) {
e.preventDefault();
this.element.classList.toggle(“active”);
}
}
// toggle_controller.js import { Controller } from "@hotwired/stimulus"; export default class extends Controller { toggle(e) { e.preventDefault(); this.element.classList.toggle("active"); } }
Good
<!– index.html –>
<a href=“#” data-controller=“toggle” data-action=“click->toggle#toggle” data-toggle-active-class=“active”>
Toggle
</a>
<!-- index.html --> <a href="#" data-controller="toggle" data-action="click->toggle#toggle" data-toggle-active-class="active"> Toggle </a>
// toggle_controller.js
import { Controller } from “@hotwired/stimulus”;
export default class extends Controller {
static classes = [“active”];
toggle(e) {
e.preventDefault();
this.element.classList.toggle(this.activeClass);
}
}
// toggle_controller.js import { Controller } from "@hotwired/stimulus"; export default class extends Controller { static classes = ["active"]; toggle(e) { e.preventDefault(); this.element.classList.toggle(this.activeClass); } }
Rationale
Late binding of dependencies (in the simplest case above, the value of a CSS class. Other examples may include the ID of a DOM element or a CSS selector) ensures that your controller is re-usable across multiple use cases.
Simply moving that value out of the controller into a dataset property will make your controllers more flexible, and you’ll have to write less specialized JavaScript in favor of more adaptable controllers that allow dependencies to be injected and thus obey the Single Reponsibility Principle.