Das Herzstück von HTMX: Trigger und fortgeschrittene Steuerungstechniken
In den bisherigen Artikeln haben wir die grundlegenden Methoden kennengelernt, um mit HTMX Anfragen an den Server zu senden.
Dabei haben wir festgestellt, dass man mit Attributen wie hx-get, hx-post, hx-put und hx-delete bereits viele Ajax-Funktionen ohne JavaScripts fetch() implementieren kann.
Doch wenn man HTMX verwendet, möchte man oft nicht nur was gesendet wird, sondern auch wann die Anfrage gesendet wird, steuern.
Hier kommt hx-trigger ins Spiel.
Während hx-get oder hx-post festlegen, "was getan werden soll", bestimmt hx-trigger, "wann es getan werden soll".
Ohne hx-trigger würde HTMX lediglich wie ein einfaches Ajax-Tool wirken, das Anfragen nur bei Button-Klicks sendet. Doch erst mit hx-trigger beginnt der wahre Reiz von HTMX.
Beispielsweise sind folgende Dinge ohne JavaScript-Code möglich:
-
Suchanfragen erst nach Beendigung der Eingabe senden
-
Mehrfachklicks innerhalb kurzer Zeit verhindern
-
Automatisches Neuladen in regelmäßigen Abständen
-
Elemente nur laden, wenn sie auf dem Bildschirm sichtbar werden
-
Anfragen nur unter bestimmten Bedingungen senden
-
Prioritäten anpassen, um Kollisionen zwischen verschiedenen Anfragen zu vermeiden
Anfangs dachte ich auch: "Warum HTMX nutzen, wenn ein paar Zeilen fetch() genügen?" Ich sah HTMX nur als einfaches Ajax-Tool. Doch meine Einstellung änderte sich komplett, nachdem ich die mächtigen Steuerungsfunktionen von hx-trigger erlebt hatte.
In diesem Artikel werden wir die Trigger und fortgeschrittenen Steuerungstechniken zusammenfassen, die als das wahre Herzstück von HTMX gelten.

HTMX ist mehr als nur ein Button-Tool
Wer HTMX zum ersten Mal kennenlernt, beginnt meist mit Beispielen wie diesem:
<button hx-get="/hello/" hx-target="#result">
불러오기
</button>
<div id="result"></div>
Auf den ersten Blick könnte man meinen, HTMX sei lediglich ein "Tool, das Ajax-Anfragen bei Button-Klicks sendet".
Das ist zwar schon sehr praktisch, aber es ist nur ein kleiner Teil dessen, was HTMX kann.
Das wirklich Entscheidende ist, dass man nicht nur die Anfrage selbst, sondern auch den Zeitpunkt und die Bedingungen für deren Auslösung direkt in HTML deklarieren kann.
Zum Beispiel:
-
Bei einer Suchleiste ist es eine schlechte UX, bei jedem Tastendruck eine Anfrage an den Server zu senden. Viel natürlicher wäre es, wenn die Anfrage erst 500ms nach Beendigung der Eingabe gesendet wird.
-
Manchmal möchte man auch, dass ein Button nicht bei einem einfachen Klick, sondern nur bei einem Klick mit gedrückter Strg-Taste funktioniert.
-
Oder man möchte Daten erst dann abrufen, wenn ein bestimmtes Element durch Scrollen auf dem Bildschirm sichtbar wird.
Wenn man für solche Fälle jedes Mal JavaScript schreiben müsste, würde der Code schnell unübersichtlich werden. HTMX hingegen ermöglicht es, diese Steuerungen weitgehend ohne eine einzige Zeile JavaScript, nur durch die Kombination von Attributen, auszudrücken.
Das ist wirklich erstaunlich. Der Schock, den ich empfand, als ich hx-trigger in HTMX zum ersten Mal sah, war vielleicht vergleichbar mit dem Schock eines C++-Entwicklers, der zum ersten Mal Python-Code sieht und denkt: "Was? Keine Typdeklarationen??"
Standard-Trigger: click, change, submit
Zunächst ist wichtig zu wissen, dass HTMX bereits so konzipiert ist, dass es gut mit den Standardverhaltensweisen von HTML-Elementen harmoniert.
Beispielsweise sind Buttons standardmäßig mit click, Formulare mit submit und Eingabeelemente je nach Situation natürlich mit Events wie change verknüpft.
<button hx-get="/load/" hx-target="#result">
가져오기
</button>
Dieser Button sendet eine Anfrage bei Klick, auch wenn hx-trigger="click" nicht explizit angegeben ist.
Das Gleiche gilt für Formulare.
<form hx-post="/submit/" hx-target="#result">
<input type="text" name="title">
<button type="submit">전송</button>
</form>
In diesem Fall wird die Anfrage beim Absenden des Formulars ausgelöst.
Das bedeutet, HTMX verhält sich in sehr grundlegenden Szenarien bereits recht intelligent. Doch der interessante Teil beginnt hier:
Über die Standardwerte hinauszugehen und den gewünschten Zeitpunkt und die Bedingungen direkt zu deklarieren. Genau das wollen wir tun.
hx-trigger: Häufig verwendete Standardereignisse vs. HTMX-spezifische Trigger
Zunächst ist es wichtig, die folgende Tabelle zu verstehen. Der Kernpunkt ist: Die vom Browser bereitgestellten Standard-DOM-Ereignisse sind selbstverständlich nutzbar + es gibt einige HTMX-spezifische Trigger.
| Kategorie | Wert | Bedeutung | Häufige Anwendung | Beispiel |
|---|---|---|---|---|
| Standardereignis | click |
Bei Klick | Button, Link, Aktionsausführung | hx-trigger="click" |
| Standardereignis | input |
Bei jeder Änderung des Eingabewerts | Echtzeitsuche, Autovervollständigung | hx-trigger="input changed delay:500ms" |
| Standardereignis | change |
Wenn der Wert endgültig geändert wurde | select, checkbox, Eingabeübernahme nach Blur |
hx-trigger="change" |
| Standardereignis | submit |
Bei Formularübermittlung | Formularversand | hx-trigger="submit" |
| Standardereignis | keyup |
Beim Loslassen einer Taste | Tastatureingabe-basierte Suche, schnelle Reaktion | hx-trigger="keyup delay:500ms" |
| Standardereignis | keydown |
Beim Drücken einer Taste | Hotkeys, Tastaturinteraktion | hx-trigger="keydown[from:body]" |
| Standardereignis | mouseup |
Beim Loslassen der Maustaste | Reaktion nach Drag/Auswahl | hx-trigger="mouseup" |
| HTMX-spezifisch | load |
Sobald das Element geladen ist | Verzögertes Laden, initiale Datenfüllung | hx-trigger="load" |
| HTMX-spezifisch | revealed |
Wenn das Element auf dem Bildschirm sichtbar wird | Unendliches Scrollen, Lazy Loading | hx-trigger="revealed" |
| HTMX-spezifisch | intersect |
Wenn das Element den Viewport kreuzt | Präziseres Lazy Loading, Scroll-basiertes Laden | hx-trigger="intersect once" |
| HTMX-spezifische Syntax | every 5s |
In regelmäßigen Abständen | Polling, Statusaktualisierung | hx-trigger="every 5s" |
| Benutzerdefiniertes Ereignis | my-custom-event |
Bei selbst definiertem Ereignis | Server-Header, JS-Integration, lose Event-Architektur | hx-trigger="itemSaved from:body" |
| Modifier | delay:500ms |
Anfrage nur, wenn innerhalb der angegebenen Zeit keine weiteren Ereignisse auftreten | Debouncing, Optimierung der Echtzeitsuche | hx-trigger="keyup delay:500ms" |
| Modifier | throttle:1s |
Begrenzt wiederholte Anfragen innerhalb kurzer Zeit | Schutz vor Mehrfachklicks, Unterdrückung übermäßiger Anfragen | hx-trigger="click throttle:1s" |
| Modifier | once |
Begrenzt die Auslösung auf einmal | Erstes Laden, einmaliges Ereignis | hx-trigger="intersect once" |
| Modifier | changed |
Anfrage nur, wenn der Wert tatsächlich geändert wurde | Optimierung von Eingabefeldern, Vermeidung unnötiger Anfragen | hx-trigger="input changed delay:500ms" |
| Modifier | from:body |
Ziel der Ereigniserkennung auf ein anderes Element festlegen | Globaler Ereignisempfang, benutzerdefinierte Ereignisverarbeitung | hx-trigger="itemSaved from:body" |
| Modifier | [condition] |
Anfrage nur, wenn die Bedingung erfüllt ist | Hilfstasten-Kombination, Eingabewertlängenbedingung | hx-trigger="click[ctrlKey]" / hx-trigger="keyup[value.length > 1]" |
| Modifier | consume |
Verhindert die Weitergabe des Ereignisses an übergeordnete Elemente | Vermeidung von Kollisionen bei verschachtelten HTMX-Anfragen | hx-trigger="click consume" |
| Modifier | queue:first |
Bei Warteschlangenbildung neuer Ereignisse nur das erste beibehalten | Beibehaltung der ersten Anfrage bei kontinuierlicher Eingabe | hx-trigger="input queue:first" |
| Modifier | queue:last |
Bei Warteschlangenbildung neuer Ereignisse nur das letzte beibehalten | Suchleiste, Autovervollständigung | hx-trigger="input queue:last" |
| Modifier | queue:all |
Alle aufgetretenen Ereignisse in der Warteschlange beibehalten | Wenn alle Ereignisse sequenziell verarbeitet werden müssen | hx-trigger="input queue:all" |
| Modifier | queue:none |
Neue Ereignisse ignorieren, wenn eine Anfrage läuft | Komplette Unterdrückung von Duplikatanfragen | hx-trigger="click queue:none" |
Der hx-trigger-Wert setzt sich normalerweise aus einem Ereignis (event) zusammen, dem bei Bedarf Filter und Modifier angehängt werden.
Man liest es also in der Reihenfolge: "Wenn etwas passiert (event), unter welcher Bedingung (filter), und wie soll es verarbeitet werden (modifier)?"
Die Form ist typischerweise event[filter] modifier modifier.
<input
hx-get="/search/"
hx-trigger="keyup[value.length > 1] changed delay:500ms">
-
keyup→ Beim Loslassen einer Taste -
[value.length > 1]→ Nur wenn der Eingabewert länger als 1 Zeichen ist -
changed delay:500ms→ Anfrage nur, wenn der Wert geändert wurde und 0,5 Sekunden lang keine weitere Eingabe erfolgt ist
Einige nützliche Beispiele
Obwohl die obige Tabelle bereits eine gute Übersicht bietet, möchte ich Ihnen noch einige meiner bevorzugten Trigger-Beispiele vorstellen.
Anfragen nur nach Beendigung der Eingabe: delay
Beim Erstellen von Funktionen wie der automatischen Vervollständigung in Suchfeldern oder Echtzeitfilterung kann das Senden einer Anfrage bei jedem Tastendruck des Benutzers den Server belasten und die Benutzererfahrung als unruhig empfunden werden.
Hier sorgt delay für ein viel flüssigeres Erlebnis.
<input type="text"
name="q"
hx-get="/search/"
hx-trigger="keyup delay:500ms"
hx-target="#search-result"
placeholder="검색어를 입력하세요">
<div id="search-result"></div>
Dieser Code sendet nicht sofort eine Anfrage, sobald der Benutzer eine Taste drückt. Stattdessen wird die Anfrage erst 500ms nach Beendigung der Eingabe gesendet.
Dies ist im Wesentlichen Debouncing.
Um dies mit JavaScript zu implementieren, müsste man einen Timer setzen, den vorherigen Timer abbrechen und einen neuen setzen. Mit HTMX erledigt man das einfach über ein Attribut.
Bei Such-, Auto-Vervollständigungs- und Filter-UIs ist diese Funktion fast schon Standard.
Nicht zu oft senden: throttle
Während sich delay so anfühlt, als würde man "nach Beendigung der Eingabe kurz warten und dann senden", zielt throttle eher darauf ab, "zu häufige Anfragen innerhalb kurzer Zeit zu begrenzen".
<button hx-post="/like/"
hx-trigger="click throttle:1s"
hx-target="#like-count">
좋아요
</button>
In diesem Fall kann man steuern, dass selbst bei sehr schnellem, wiederholtem Drücken des Buttons innerhalb einer Sekunde keine übermäßigen Anfragen aufeinanderfolgend gesendet werden.
Dies ist in folgenden Situationen sehr nützlich:
-
Verhinderung von Mehrfachklicks
-
Blockieren zu schneller, wiederholter Anfragen
-
Reduzierung der Serverlast
-
Verhindern, dass versehentlich dieselbe Aktion mehrmals ausgeführt wird
Besonders bei Buttons wie "Gefällt mir", "Speichern", "Aktualisieren" oder "Synchronisieren" sollte man dies in Betracht ziehen.
Automatische Anfragen in regelmäßigen Abständen: every
Eine überraschend attraktive Funktion von HTMX ist every.
Wenn Sie einen bestimmten Bereich in regelmäßigen Abständen vom Server neu laden möchten, müssen Sie keine separate Polling-Logik in JavaScript schreiben.
<div hx-get="/server-status/"
hx-trigger="every 5s"
hx-target="this">
서버 상태를 불러오는 중...
</div>
Dieser Code sendet alle 5 Sekunden eine GET-Anfrage an /server-status/ und aktualisiert sich selbst mit der Antwort.
Die Einsatzmöglichkeiten sind vielfältig:
-
Serverstatus-Überwachung
-
Anzeige des Arbeitsfortschritts
-
Aktualisierung von Dashboard-Zahlen
-
Aktualisierung der Anzahl von Chat-Benachrichtigungen
-
Anzeige einfacher Echtzeitinformationen in der Admin-Oberfläche
Natürlich ist Vorsicht geboten, da eine zu kurze Frequenz den Server belasten kann. Doch richtig eingesetzt, ist es ein großer Reiz von HTMX, solche Funktionen allein mit HTML-Attributen lösen zu können.
Nur unter bestimmten Bedingungen aktivieren: Ereignisfilterung
Die Ereignisfilterfunktion ist wirklich hervorragend. Als ich sie zum ersten Mal sah, empfand ich große Dankbarkeit gegenüber den Entwicklern und Mitwirkenden von HTMX. Es ist großartig.
In HTMX können Sie Bedingungen an Ereignisse anhängen, um Anfragen auf bestimmte Situationen zu beschränken.
<button hx-delete="/post/123/"
hx-trigger="click[ctrlKey]"
hx-target="#post-123"
hx-swap="outerHTML">
삭제
</button>
Dieser Code funktioniert nicht bei einem einfachen Klick. Die Löschanfrage wird nur ausgelöst, wenn die Strg-Taste gedrückt gehalten und gleichzeitig geklickt wird.
Solche bedingten Trigger sind zwar kleine Details, können die UX aber deutlich verfeinern.
Zum Beispiel:
-
Ausführung nur bei gedrückter bestimmter Zusatztaste
-
Ausführung nur, wenn ein Kontrollkästchen ausgewählt ist
-
Suche nur, wenn der Eingabewert eine bestimmte Länge überschreitet
-
Keine Anfrage bei leerem String
Dies lässt sich in ähnlicher Weise erweitern.
<input type="text"
name="q"
hx-get="/search/"
hx-trigger="keyup[value.length > 1] delay:400ms"
hx-target="#result">
Auf diese Weise können Sie Anfragen nur senden lassen, wenn der Suchbegriff aus mehr als zwei Zeichen besteht.
load: Ausführung, sobald die Seite oder das Element bereit ist
Manchmal möchte man bestimmte Bereiche einer Seite sofort nach dem Laden mit Daten füllen. Dazu gehören beispielsweise Dashboard-Statistiken, Empfehlungslisten oder Benachrichtigungsbereiche.
Hier kann load verwendet werden.
<div hx-get="/dashboard/summary/"
hx-trigger="load"
hx-target="this">
요약 정보를 불러오는 중...
</div>
Dieser Code sendet sofort eine Anfrage, sobald das entsprechende Element geladen ist, und ersetzt oder aktualisiert sich selbst mit der Antwort.
Es kann auch so genutzt werden, dass nicht die gesamte Seite vom Server gerendert wird, sondern nur relativ schwere Bereiche später geladen werden. Das heißt, es eignet sich gut für einfache Lazy-Loading-Muster.
revealed: Ausführung, wenn auf dem Bildschirm sichtbar
Dieser Trigger ist sehr intuitiv benannt. Er sendet eine Anfrage, wenn ein Element auf dem Bildschirm erscheint.
<div hx-get="/posts/next-page/"
hx-trigger="revealed"
hx-swap="afterend">
더 많은 글을 불러오는 중...
</div>
Diese Methode wird häufig zur Implementierung von Infinite Scroll verwendet.
Sobald der Benutzer nach unten scrollt und das entsprechende Element sichtbar wird, wird der nächste Datenblock geladen und angehängt. Es ist sehr attraktiv, dass man eine recht natürliche Infinite-Scroll-Funktion implementieren kann, ohne den Intersection Observer direkt mit JavaScript handhaben zu müssen.
Allerdings ist revealed zwar einfach und bequem, kann aber unzureichend sein, wenn eine sehr detaillierte Steuerung erforderlich ist.
In solchen Fällen passt intersect besser.
intersect: Präzisere Handhabung der Viewport-Überschneidung
Während revealed eher das Gefühl von "Ist es sichtbar geworden?" vermittelt, geht intersect darum, wie und wann ein Element den Viewport kreuzt, präziser zu steuern.
<div hx-get="/analytics/block/"
hx-trigger="intersect once"
hx-target="this">
분석 영역 로딩 중...
</div>
In diesem Beispiel wird eine Anfrage nur einmal gesendet, sobald das Element den Viewport kreuzt.
Diese Methode eignet sich gut für folgende Fälle:
-
Schwere Abschnitte auf langen Seiten später laden
-
Aufzeichnung des Zeitpunkts der Anzeigen-/Banner-Einblendung
-
Daten nur laden, wenn ein bestimmter Bereich tatsächlich sichtbar wird
-
Inhalt schrittweise beim Scrollen füllen
Es ist eine Funktion, die man bei Infinite Scroll, Lazy Loading und bildschirmoptimierten Anwendungen unbedingt einmal ausprobieren sollte.
Kommunikation zwischen Server und Client: Der HX-Trigger-Header
Wenn man HTMX weiterhin verwendet, kommt irgendwann der Punkt, an dem das Senden von Anfragen durch den Browser allein nicht mehr ausreicht. Nachdem die Serverantwort abgeschlossen ist, möchte man möglicherweise, dass auch andere UI-Elemente gleichzeitig interagieren.
Beispielsweise in diesen Situationen:
-
Nach dem Speichern die Liste neu laden
-
Eine Erfolgsmeldung für das Speichern anzeigen
-
Auch die Zählerzahl gleichzeitig aktualisieren
Man könnte all dies mit clientseitigem JavaScript verknüpfen, aber mit HTMX kann der Server über Header Ereignisse auslösen.
Zum Beispiel in einer Django-View:
from django.http import HttpResponse
import json
def save_item(request):
response = HttpResponse("<div>저장 완료</div>")
response["HX-Trigger"] = json.dumps({
"itemSaved": {
"message": "저장이 완료되었습니다."
}
})
return response
Der Client kann dieses Ereignis dann nutzen.
<div hx-get="/items/list/"
hx-trigger="itemSaved from:body"
hx-target="#item-list">
</div>
<div hx-get="/toast/success/"
hx-trigger="itemSaved from:body"
hx-target="#toast-area">
</div>
Der Grund, warum diese Struktur gut ist, ist klar.
Der Server, der die Speicheranfrage verarbeitet hat, sendet nicht nur "Speichern abgeschlossen HTML", sondern kann auch Signale für nachfolgende Reaktionen wie "Jetzt die Liste aktualisieren" oder "Benachrichtigung anzeigen" senden.
Das bedeutet, Server und Client kommunizieren nicht mehr nur in einer einfachen Anfrage-Antwort-Beziehung, sondern in einer lockerer gekoppelten Ereignisstruktur.
Was klein und unscheinbar beginnt, wird umso mächtiger, je größer die Benutzeroberfläche wird.
Fazit
In diesem Artikel haben wir die zentralen Steuerattribute von HTMX, insbesondere die fortgeschrittenen Funktionen rund um hx-trigger, zusammengefasst.
Zusammenfassend lässt sich sagen:
-
hx-triggerbestimmt, wann eine Anfrage ausgelöst wird. -
Das Trigger-Attribut umfasst sowohl die Standard-DOM-Ereignisse des Browsers als auch HTMX-spezifische Ereignisse.
-
Bedingte Trigger ermöglichen es, Anfragen nur in bestimmten Situationen auszulösen.
-
Mit Modifier-Attributen können Ereignisse feinjustiert werden.
-
Der
HX-Trigger-Header ermöglicht es dem Server, Folgeaktionen des Clients auszulösen.
Damit lässt sich dieser Artikel zusammenfassen.
Es ist erstaunlich, dass all dies ohne eine einzige Zeile JavaScript möglich ist. Genauer gesagt: "ohne eine einzige Zeile JavaScript, die ich selbst schreibe", denn der über CDN geladene JavaScript-Code läuft ja bereits im Browser.
Lesen Sie auch :
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 1)
- Dynamische Webentwicklung vereinfachen mit Django und HTMX – Ajax (Teil 2)
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 3): Django-Integration
- Dynamische Webentwicklung mit Django und HTMX vereinfachen (Teil 4): Payload-Übertragungsarten
- Dynamische Webentwicklung vereinfachen mit Django und HTMX: Einsatz von Form und Serializer
Es sind keine Kommentare vorhanden.