StimulusJS_Blog_Titelbild_BG

Stimulus

Von am 20.02.2022

https://stimulus.hotwired.dev/

Stimulus, ein modernes JavaScript-Framework, das ein bestehendes HTML-DOM problemlos ergänzen kann. Aber warum ist Stimulus ein nützliches Tool?

Alles in allem ist Stimulus eine ~30kb große Bibliothek, die kleine, wiederverwendbare JavaScript Bausteine beinhaltet, welche durch kleine Hinweise in HTML inkludiert werden können.

Aber wie funktioniert das Ganze?

Controller

Ein Controller ist die grundlegende Strukturierungseinheit einer Stimulus-Anwendung.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // …
}

Im Dateinamen werden mehrere Worte durch Unterstriche oder Bindestriche getrennt:

controllers/sidebar_controller.js

controllers/delete_modal_controller.js

Identifiers sind die Namen, die verwendet werden um eine Controller-Klasse zu referenzieren. Wenn ein Element mittels data-controller Attribute hinzugefügt wird, liest Stimulus den Identifier aus dem Attribut und erstellt eine neue Instanz der Controller-Klasse.

<div data-controller="sidebar"></div>

Hier hat das Element den Controller controllers/sidebar_controller.js

Webpack

Wenn Stimulus beispielsweise mit Webpack genutzt wird, gibt es die Möglichkeit das Paket @hotwired/stimulus-webpack-helpers zu nutzen um die Controller-Klassen automatisch zu laden und zu registrieren:

import { Application } from "@hotwired/stimulus"
import { definitionsFromContext } from "@hotwired/stimulus-webpack-helpers"

window.Stimulus = Application.start()
const context = require.context("./controllers", true, /\\.js$/)
Stimulus.load(definitionsFromContext(context))

Manuelle Einbindung

Ohne den Webpack Helper muss jede Controller-Klasse manuell geladen und registriert werden z.B.:

import SidebarController from "./controllers/sidebar_controller"

application.register("sidebar", SidebarController)

Actions

Actions sind die Events, die vom DOM ausgeführt werden.

<div data-controller="sidebar">
	<button data-action="click->sidebar#open">…</button>
</div>

// controllers/sidebar_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  open(event) {
    // …
  }
}

  • click ist der Name des Event Listeners
  • sidebar ist der Name des Controllers
  • open ist der Name der Methode

Hier gibt es auch die Möglichkeit für globale Events, also Event Listeners, die auf das Fenster oder das Dokument hören. Beispielsweise:

<div data-controller="sidebar"
     data-action="resize@window->sidebar#layout">
</div>

Targets

Targets referenzieren bestimmte Elemente beim Namen.

<div data-controller="sidebar">
  <div data-sidebar-target="overlay"></div>
</div>

Die Targets werden im Controller mittels einem static targets Array definiert

// controllers/sidebar_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "overlay" ]
}

Jedes Target kann mittels this.[name]Target innerhalb des Controllers aufgerufen werden. Hier also z.B. this.overlayTarget.

Values

Ähnlich können HTML Attribute für Daten verwendet werden.

<div data-controller="sidebar"
     data-sidebar-color-value="#000">
</div>

// controllers/sidebar_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = {
    color: String
  }
}

Auf diesen Wert kann dann mittels this.colorValue zugegriffen werden.

Lifecycle Callbacks

Spezielle Methoden, ermöglichen es mit den Lifecycle Callbacks direkt zu reagieren, wenn ein Controller eine Verbindung zu einem Dokument herstellt oder getrennt wird.

Methoden:

Quelle: https://stimulus.hotwired.dev/reference/lifecycle-callbacks (15.02.2022, 12:10)

Connection

Ein Controller wird verbunden wenn entweder eines seiner Elemente im Dokument vorhanden ist oder sein Identifier in einem data-controller Attribute aufgerufen wird.

Wenn ein Controller verbunden wird, wird die connect() Methode aufgerufen.

Ein Target wird verbunden wenn entweder das Element im Dokument innerhalb des jeweiligen Controller Elements vorhanden ist oder sein Identifier vorhanden ist (data-{identifier}-target).

Wenn ein Target verbunden wird, wird die [name]TargetConnected() Methode aufgerufen, dies wird außerdem VOR der allgemeinen connect() Methode aufgerufen.

Disconnection

Ein verbundener Controller wird getrennt wenn eine “verbindenden” Bedingungen nicht mehr zutrifft. Wenn also beispielsweise das Element vom DOM, das Eltern Element enfernt oder ersetzt wird oder auch wenn das data-controller Attribute entfernt oder überschrieben wird.

In einem dieser Fälle wird die Methode disconnect() aufgerufen.

Die gleiche Vorgehensweise trifft auf die Trennung eines Targets zu hier wird [name]TargetDisconnected() aufgerufen. Dies wird ebenfalls VOR der Controller disconnect() Funktion ausgeführt.

Sidebar Beispiel

Hier ein Beispiel für eine einfache “Sidebar” Erstellung. In diesem Beispiel wird anhand von Buttons eine Sidebar ein- bzw. ausgeblendet. Hier wird mittels Webpack das script.js generiert, in welchem wie oben beschrieben, die Controller Klasse eingebunden wird.

Die Buttons rufen die Funktionen open() und close() auf, die im sidebar_controller definiert sind. In den Funktionen wird die CSS Klasse .hidden hinzugefügt bzw. entfernt.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stimulus</title>
    <link rel="stylesheet" href="/dist/css/style.css">
</head>
<body data-controller="sidebar">
    <div class="sidenav hidden" data-action="click->sidebar#close" data-sidebar-target="overlay">
        <button>Close Sidebar</button>
    </div>

    <main>
        <h1>Stimulus Sidebar</h1>
        <button data-action="click->sidebar#open">Open Sidebar</button>
    </main>

    <script src="/dist/javascript/script.js"></script>
</body>
</html>

style.scss

.sidenav {
    height: 100%;
    width: 200px;
    position: fixed;
    z-index: 1;
    top: 0;
    left: 0;
    background-color: #111;
    overflow-x: hidden;
    padding: 2rem;
}

.hidden {
    visibility: hidden;
}

main {
    padding: 2rem;
}

script.js

import { Application } from "@hotwired/stimulus"
import { definitionsFromContext } from "@hotwired/stimulus-webpack-helpers"

window.Stimulus = Application.start()
const context = require.context("./controllers", true, /\\.js$/)
Stimulus.load(definitionsFromContext(context))

sidebar_controller.js

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {

    static targets = [
        "overlay"
    ]

    connect() {
        console.log("Sidebar Controller connected");
    }

    open() {
        console.log("OPEN");
        this.overlayTarget.classList.remove("hidden");
    }

    close() {
        console.log("CLOSE");
        this.overlayTarget.classList.add("hidden");
    }
}

Quellen

https://stimulus.hotwired.dev/

https://pspdfkit.com/blog/2018/introduction-to-stimulus-js/

https://gist.github.com/mrmartineau/a4b7dfc22dc8312f521b42bb3c9a7c1e

https://www.smashingmagazine.com/2020/07/introduction-stimulusjs/

https://egghead.io/lessons/javascript-fire-a-stimulus-controller-action-on-a-click-event

The comments are closed.